Django CRUD Application with VueJs as front-end | VueJs + Django Rest Framework + MySQL example – Part 3: VueJs Client

django-vue-crud-example-django-rest-api-mysql-feature-image

This tutorial is part 3 of Django-VueJs-MySQL series. Today, we will create Vuejs Client to make HTTP request & receive response from Django Server.

>> Part 1: Overview
>> Part 2: Django Server

Video

[Coming soon…]

VueJs Client Overview

Goal

The image below shows overview about Vuejs Components that we will create:

django-vue-crud-example-django-rest-api-mysql-client-components

Project Structure

django-vue-crud-example-django-rest-api-mysql-vue-project-structure

– package.json with 3 main modules: vuevue-routeraxios.
– 4 components: CustomersListCustomerAddCustomerSearchCustomer.
– router.js defines routes, each route has a path and maps to a component.
– http-common.js initializes HTTP Client with baseUrl and headers for axios HTTP methods.
– vue.config.js configures port for Vue App.

For more details about how to use Vue Router in this example, please visit:
Vue Router example – with Nav Bar, Dynamic Route & Nested Routes

Setup VueJs Project

Init Project

Point cmd to the folder you want to save Project folder, run command:
vue create vue-django

You will see 2 options, choose default

vue-create-project-config

Add Vue Router to Project

– Run command: npm install vue-router.
– Import router to src/main.js:

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

Initialize HTTP Client

Install axios with command: npm install axios.
Then create http-common.js file:

import axios from 'axios';

export default axios.create({
    baseURL: 'http://localhost:8000/api',
    headers: {
        'Content-type': 'application/json'
    }
});

Configure Port for Vue App

vue.config.js

module.exports = {
  devServer: {
    port: 4200
  }
}

Implement VueJs Client App

Components

List of Items

components/CustomersList.vue

<template>
    <div class="list row">
        <div class="col-md-6">
            <h4>Customers List</h4>
            <ul>
                <li v-for="(customer, index) in customers" :key="index">
                    <router-link :to="{
                            name: 'customer-details',
                            params: { customer: customer, id: customer.id }
                        }">
                            {{customer.name}}
                    </router-link>
                </li>
            </ul>
        </div>
        <div class="col-md-6">
            <router-view @refreshData="refreshList"></router-view>
        </div>
    </div>
</template>
 
<script>
import http from "../http-common";
 
export default {
  name: "customers-list",
  data() {
    return {
      customers: []
    };
  },
  methods: {
    /* eslint-disable no-console */
    retrieveCustomers() {
      http
        .get("/customers/")
        .then(response => {
          this.customers = response.data; // JSON are parsed automatically.
          console.log(response.data);
        })
        .catch(e => {
          console.log(e);
        });
    },
    refreshList() {
      this.retrieveCustomers();
    }
    /* eslint-enable no-console */
  },
  mounted() {
    this.retrieveCustomers();
  }
};
</script>
 
<style>
.list {
  text-align: left;
  max-width: 450px;
  margin: auto;
}
</style>

Item Details

components/Customer.vue

<template>
  <div v-if="this.customer">
    <h4>Customer</h4>
    <div>
      <label>Name: </label> {{this.customer.name}}
    </div>
    <div>
      <label>Age: </label> {{this.customer.age}}
    </div>
    <div>
      <label>Active: </label> {{this.customer.active}}
    </div>
  
    <span v-if="this.customer.active" v-on:click="updateActive(false)" class="button is-small btn-primary">Inactive</span>
    <span v-else="" v-on:click="updateActive(true)" class="button is-small btn-primary">Active</span>
  
    <span class="button is-small btn-danger" v-on:click="deleteCustomer()">Delete</span>
  </div>
  <div v-else="">
    <br>
    <p>Please click on a Customer...</p>
  </div>
</template>
 
<script>
import http from "../http-common";
 
export default {
  name: "customer",
  props: ["customer"],
  methods: {
    /* eslint-disable no-console */
    updateActive(status) {
      var data = {
        id: this.customer.id,
        name: this.customer.name,
        age: this.customer.age,
        active: status
      };
 
      http
        .put("/customers/" + this.customer.id, data)
        .then(response => {
          this.customer.active = response.data.active;
          console.log(response.data);
        })
        .catch(e => {
          console.log(e);
        });
    },
    deleteCustomer() {
      http
        .delete("/customers/" + this.customer.id)
        .then(response => {
          console.log(response.data);
          this.$emit("refreshData");
          this.$router.push('/');
        })
        .catch(e => {
          console.log(e);
        });
    }
    /* eslint-enable no-console */
  }
};
</script>

Add Item

components/AddCustomer.vue

<template>
  <div class="submitform">
    <div v-if="!submitted">
        <div class="form-group">
          <label for="name">Name</label>
          <input type="text" class="form-control" id="name" required="" v-model="customer.name" name="name">
        </div>
    
        <div class="form-group">
          <label for="age">Age</label>
          <input type="number" class="form-control" id="age" required="" v-model="customer.age" name="age">
        </div>
    
        <button v-on:click="saveCustomer" class="btn btn-success">Submit</button>
    </div>
    
    <div v-else="">
      <h4>You submitted successfully!</h4>
      <button class="btn btn-success" v-on:click="newCustomer">Add</button>
    </div>
  </div>
</template>
 
<script>
import http from "../http-common";
 
export default {
  name: "add-customer",
  data() {
    return {
      customer: {
        id: 0,
        name: "",
        age: 0,
        active: false
      },
      submitted: false
    };
  },
  methods: {
    /* eslint-disable no-console */
    saveCustomer() {
      var data = {
        name: this.customer.name,
        age: this.customer.age
      };
 
      http
        .post("/customers/", data)
        .then(response => {
          this.customer.id = response.data.id;
          console.log(response.data);
        })
        .catch(e => {
          console.log(e);
        });
 
      this.submitted = true;
    },
    newCustomer() {
      this.submitted = false;
      this.customer = {};
    }
    /* eslint-enable no-console */
  }
};
</script>
 
<style>
.submitform {
  max-width: 300px;
  margin: auto;
}
</style>

Search Items

components/SearchCustomers.vue

<template>
  <div class="searchform">
    <h4>Find by Age</h4>
    <div class="form-group">
      <input type="number" class="form-control" id="age" required="" v-model="age" name="age">
    </div>

    <div class="btn-group">
      <button v-on:click="searchCustomers" class="btn btn-success">Search</button>
    </div>

    <ul class="search-result">
      <li v-for="(customer, index) in customers" :key="index">
        <h6>{{customer.name}} ({{customer.age}})</h6>
      </li>
    </ul>
  </div>
</template>
 
<script>
import http from "../http-common";

export default {
  name: "search-customer",
  data() {
    return {
      age: 0,
      customers: []
    };
  },
  methods: {
    /* eslint-disable no-console */
    searchCustomers() {
      http
        .get(`/customers/age/${this.age}/`)
        .then(response => {
          this.customers = response.data; // JSON are parsed automatically.
          console.log(response.data);
        })
        .catch(e => {
          console.log(e);
        });
    }
    /* eslint-enable no-console */
  }
};
</script>
 
<style>
.searchform {
  max-width: 300px;
  margin: auto;
}
.search-result {
  margin-top: 20px;
  text-align: left;
}
</style>

Routing

Define Routes

src/router.js

import Vue from "vue";
import Router from "vue-router";
import CustomersList from "./components/CustomersList.vue";
import AddCustomer from "./components/AddCustomer.vue";
import SearchCustomers from "./components/SearchCustomers.vue";
import Customer from "./components/Customer.vue";

Vue.use(Router);

export default new Router({
    mode: "history",
    routes: [
        {
            path: "/",
            name: "customers",
            alias: "/customer",
            component: CustomersList,
            children: [
                {
                    path: "/customers/:id",
                    name: "customer-details",
                    component: Customer,
                    props: true
                }
            ]
        },
        {
            path: "/add",
            name: "add",
            component: AddCustomer
        },
        {
            path: "/search",
            name: "search",
            component: SearchCustomers
        }
    ]
});

App template with Navbar and router-view

src/App.vue:

<template>
    <div id="app" class="container-fluid">
        <div class="site-info">
            <h1>grokonez</h1>
            <h3>Vue Django example</h3>
        </div>
        <nav>
            <router-link class="btn btn-primary" to="/">Customers</router-link>
            <router-link class="btn btn-primary" to="/add">Add</router-link>
            <router-link class="btn btn-primary" to="/search">Search</router-link>
        </nav>
        <br/>
        <router-view/>
    </div>
</template>
 
<script>
export default {
  name: "app"
};
</script>
 
<style>
.site-info {
  color: blue;
  margin-bottom: 20px;
}
 
.btn-primary {
  margin-right: 5px;
}
 
.container-fluid {
  text-align: center;
}
</style>

Run

– Run Django server with command: python manage.py runserver .
– Vue.js Client: npm run serve.

Open Browser with Url: http://localhost:4200/.

Source Code

vue-rest-client-django-mysql



By grokonez | March 3, 2019.

Last updated on April 3, 2021.



Related Posts


1 thought on “Django CRUD Application with VueJs as front-end | VueJs + Django Rest Framework + MySQL example – Part 3: VueJs Client”

  1. Hey

    Great article. Would you mind maybe making a full example with the django bits included? API authentication etc?
    And github/lab/etc, would be more convenient to browse the source.

    Best wishes,
    Z

Got Something To Say:

Your email address will not be published. Required fields are marked *

*