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:

Project Structure

– package.json with 3 main modules: vue
, vue-router
, axios
.
– 4 components: CustomersList, Customer, AddCustomer, SearchCustomer.
– 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

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>ozenero</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/
.