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

Source Code

vue-rest-client-django-mysql

43 thoughts 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

  2. Great blog! Do you have any helpful hints for aspiring writers?
    I’m planning to start my own website soon but I’m a
    little lost on everything. Would you recommend starting with a
    free platform like WordPress or go for a paid option?
    There are so many choices out there that I’m totally confused ..
    Any recommendations? Many thanks!

  3. It’s in point of fact a nice and helpful piece of information. I’m happy that you simply shared this helpful information with us.
    Please stay us up to date like this. Thank you for sharing.

  4. Hey there! This is my first visit to your blog!
    We are a group of volunteers and starting a new project
    in a community in the same niche. Your blog provided us valuable information to work on. You have done
    a outstanding job!

  5. fantastic submit, very informative. I ponder why the opposite experts of this
    sector do not realize this. You must continue your writing.
    I’m sure, you have a great readers’ base already!

  6. I like what you guys are up too. This sort of clever work and exposure!

    Keep up the very good works guys I’ve incorporated you guys to blogroll.

  7. 761768 850992It was any exhilaration discovering your web site yesterday. I arrived here nowadays hunting new issues. I was not necessarily frustrated. Your tips following new approaches on this thing have been helpful plus an superb assistance to personally. We appreciate you leaving out time to write out these items and then for revealing your thoughts. 67028

  8. 193587 64801The subsequent time I read a weblog, I hope that it doesnt disappoint me as a whole lot as this 1. I mean, I know it was my option to read, but I truly thought youd have something attention-grabbing to say. All I hear can be a bunch of whining about something that you possibly can repair really should you werent too busy on the lookout for attention. 321718

  9. Hi! This is my first comment here so I just wanted
    to give a quick shout out and tell you I really enjoy reading your articles.
    Can you suggest any other blogs/websites/forums that cover the same subjects?
    Thank you!

  10. You really make it appear really easy along with your presentation however I in finding this topic to be actually one thing which I believe I would never understand.It kind of feels too complex and extremely large for me. I’m having a look forward toyour next put up, I’ll attempt to get the dangle of it!

  11. Normally I do not read article on blogs, however I wish to say that this write-up very compelled
    me to check out and do so! Your writing style has been surprised me.
    Thank you, quite nice article.

  12. The Citizen Nighthawk CA295-58E does not boast of fancy technology, aside from Eco-Drive technology. If you are new to this, the watch records any type of kind of light and converts it into energy.

  13. I simply desired to make a quick comment in order to express gratitude for your requirements for people wonderful pointers you are posting at this site. Time consuming internet investigation has towards the end for the day been rewarded with high-quality strategies to present to my guests. I would claim that many of us readers are really endowed to happen in an incredible network with biggest reason so many marvellous those with useful hints. Personally i think quite privileged to have used your webpages and check toward really more fabulous minutes reading here. Thank you for many things.

  14. I’ve been exploring for a little for any high-quality articles or blog posts on this sort of area . Exploring in Yahoo I ultimately stumbled upon this website. Studying this information So i’m satisfied to convey that I’ve a very excellent uncanny feeling I found out exactly what I needed. I most unquestionably will make certain to don’t omit this website and provides it a glance a continuing.

  15. I am thankful that I discovered this web blog , just the right information that I was searching for! .Typically, Apple announces a press event about a week in advance, and products tend to ship within a couple days to a couple weeks of that event.

  16. Aw, it was an exceptionally good post. In idea I must set up writing such as this additionally – spending time and actual effort to have a very good article… but exactly what can I say… I procrastinate alot and also no means find a way to get something accomplished.

Leave a Reply

Your email address will not be published.