Django integration
How to use Vue with Django - free starter
This guide will provide you with a free template for a Django application, with MongoDB database and Vue + Bootstrap 5 front-end.
Prerequisites
Before starting the project make sure to install the following utilities:
Creating a new Django application
Let's create a fresh Django application so we can go through all the steps together. For this tutorial we'll be using MySQL database.
Step 1
Creating a MySQL database
In order to create a new database you need to run the following command
mdb database init -db mysql8
- Create a new user
- Provide username, password, database name and description.
CLI will display your username, password, database name and connections string. Now you can go to phpMyAdmin where you will be able to handle the administration of the MySQL database.
Note Note: Your final username and database name may differ from your inputs. MDB GO may add some characters to randomize username and database name.
Important Do not close your terminal window until you save your credentials somewhere. This is the only time we will show you your database password. If you won't save it you'll loose it.
Step 2
Creating Django API.
Install Django on your computer.
Note: If you are getting errors, try typing these commands in cmd instead of in the vsc terminal or check your Python environment settings.
python -m pip install -e django/
py -m pip install Django
Step 3
Now we have to install the necessary modules that are needed for the Django backend to work properly.
To create Django web API we will need Django Rest Framework. We should also install module that will be responsible for handling CORS issues in our developement application.
pip install djangorestframework
pip install django-cors-headers
Step 4
Navigate to your project directory, i.e. mdb-vue-django-app
.
Let's create a Django project by typing the code below. We are naming our project as MDBdjangoAPI
but you can go with whatever you want.
django-admin startproject MDBdjangoAPI
Step 5
Now that we have the project installed, let's create a new app in which we will put all the functions our REST API will need. Navigate to the newly created directory with django project and enter the following the code.
cd MDBdjangoAPI
python manage.py startapp restAPI
cd MDBdjangoAPI
py manage.py startapp restAPI
Step 6
Register the app and new modules in settings.py
. If you are not sure about the name of your app, go to restAPI/apps.py
and copy the class name. We have to register corsheaders
in middlware section aswell.
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'restAPI.apps.RestapiConfig'
]
CORS_ORIGIN_ALLOW_ALL = True
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
...
Step 7
Nowe we have to create a model needed for our app. We need _id
field which value will be autofilled. We also need name
and desc
with max length set as below.
from django.db import models
# Create your models here.
class Tasks(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=60)
desc = models.CharField(max_length=255)
Step 8
Django requires to install mysqlclient
in version 1.4.0
or higher so it can work with MySQL properly. Without it you wouldn't be able to communicate with database and manipulate its contents.
pip install mysqlclient
Step 9
Go to settings.py
, go to DATABASES
section and add the database connection details. Change the values between brackets
for the ones you got after creating a new MySQL Database from our starter.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '[Your database name]',
'USER': '[Your user name]',
'PASSWORD': '[Your password]',
'HOST': 'mysql.db.mdbgo.com',
'PORT': '3306'
}
}
Step 10
Make migration with our models to the database.
python manage.py makemigrations restAPI
py manage.py makemigrations restAPI
Step 11
Check restAPI/migrations/0001_initial_py
if everything is correct and then migrate the data. Now you can see the changes after logging to https://phpmyadmin.mdbgo.com/
python manage.py migrate restAPI
py manage.py migrate restAPI
Step 12
Create serializers for our models. This will allow us to convert complex types into python datatypes that can be rendered in json format.
from rest_framework import serializers
from restAPI.models import Tasks
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Tasks
fields = ('_id', 'name', 'desc')
Step 13
Open views.py
and start working on API methods we'll be using. We are going to create GET, POST, PUT and DELETE
endpoints that will support the functionality of the front-end app.
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from django.http.response import JsonResponse
from restAPI.models import Tasks
from restAPI.serializers import TaskSerializer
# Create your views here.
@csrf_exempt
def taskAPI(request, id=0):
if request.method == 'GET':
tasks = Tasks.objects.all()
tasks_serializer = TaskSerializer(tasks, many=True)
return JsonResponse(tasks_serializer.data, safe=False)
elif request.method == 'POST':
task_data = JSONParser().parse(request)
tasks_serializer = TaskSerializer(data=task_data)
if tasks_serializer.is_valid():
tasks_serializer.save()
return JsonResponse("Task Added Succesfully", safe=False)
return JsonResponse("Task Failed to Add", safe=False)
elif request.method == 'PUT':
task_data = JSONParser().parse(request)
task = Tasks.objects.get(_id=id)
tasks_serializer = TaskSerializer(task, data=task_data)
if tasks_serializer.is_valid():
tasks_serializer.save()
return JsonResponse("Task Updated successfully", safe=False)
return JsonResponse("Task Failed to Update")
elif request.method == "DELETE":
task = Tasks.objects.get(_id=id)
task.delete()
return JsonResponse("Task Deleted", safe=False)
Step 14
Create a new urls.py
file where we will define routes for our API methods.
from django.urls import path
from restAPI import views
urlpatterns = [
path('tasks/', views.taskAPI),
path('tasks/<slug:id>', views.taskAPI)
]
Step 15
Add new path to urls.py
in the main project directory.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('restAPI.urls'))
]
Step 16
Make migrations and run backend server. Copy the link to your app and paste it to your browser. You should see an empty array after adding /tasks
at the end.
python manage.py makemigrations restAPI
python manage.py migrate restAPI
python manage.py runserver
py manage.py makemigrations restAPI
py manage.py migrate restAPI
py manage.py runserver
Creating MDB Vue application
If our backend is working correctly we should start creating a new Vite application. If you have encountered any problems, you should go back and try each step again.
Note: Don't forget to go back to your root folder before next step. Folders MDBdjangoAPI
and mdb5-free-vue
should be in the same directory.
Step 1
Create a new vite project with our MDB starter. Run the command below and select MDB5 Free Vue
starter.
mdb init
Your folder structure should look like this
Step 2
Let's make some changes to the created vue app. First we need to install axios
inside our mdb5-free-vue
directory.
npm install axios
Remove style.css
file (don't forget to delete it from main.ts
file) and remove HelloWorld
file from components directory.
Step 3
Let's create a .env
file inside a mdb5-free-vue directory. We have to add VITE_
before the name of your variable, because it's the only way to expose them to Vite-processed code. Don't forget to change LINK_TO_YOUR_BACKEND
to the link your backend is running right now.
VITE_API = "LINK_TO_YOUR_BACKEND_APP"
Step 4
Add new content to Home.vue
file inside the views
directory.
Since our starter database contains some sample models and routes, let's use them. We will create an application that will show a list of tasks. We also intend to create a functonality for adding new tasks, changing their content and removing them.
We have already prepared the code for you, so go ahead and copy and paste it into App.vue
.
Ok, so what's actually going on there. We use MDB components, MDBBtn, MDBModal, MDBListGroup, MDBInputs
and few other. The modal will be responsible to show inputs that will allow you to add, edit and send tasks to the database. The Manage tasks
button, gives possibilty to modify or remove tasks. At the end, the list group will display our data.
<template>
<MDBContainer class="mt-5">
<MDBRow class="pt-5">
<MDBCol class="text-center">
<MDBBtn color="primary" @click="taskModal = true">Add task</MDBBtn>
</MDBCol>
</MDBRow>
<MDBRow class="mt-3 p-5" style="min-height: 40vh">
<MDBCol class="d-flex justify-content-center align-items-center">
<div v-if="taskList.length === 0">
Nothing to display. Add a few tasks.
</div>
<MDBListGroup v-else class="list-group-light" style="min-width: 22rem">
<MDBListGroupItem
class="d-flex justify-content-between align-items-center gap-5"
v-for="task in taskList"
:key="task._id"
>
<div>
<div class="fw-bold">
{{ task.name }}
</div>
<div class="text-muted">{{ task.desc }}</div>
</div>
<div>
<MDBIcon
class="text-primary me-3"
title="edit"
icon="pen"
style="cursor: pointer"
@click="() => editModal(task)"
/>
<MDBIcon
class="text-danger"
title="delete"
icon="trash"
style="cursor: pointer"
@click="() => deleteTask(task._id)"
/>
</div>
</MDBListGroupItem>
</MDBListGroup>
</MDBCol>
</MDBRow>
</MDBContainer>
<MDBModal
id="addNewTaskModal"
tabindex="-1"
labelledby="addNewTaskModalLabel"
v-model="taskModal"
>
<MDBModalHeader>
<MDBModalTitle id="exampleModalLabel">{{
isEdited.edited ? "Edit task" : "Add task"
}}</MDBModalTitle>
</MDBModalHeader>
<MDBModalBody>
<form>
<div class="my-4">
<MDBInput
label="Name"
type="text"
v-model="newTaskName"
counter
:maxlength="60"
/>
</div>
<div class="my-4">
<MDBInput
label="Description"
type="text"
v-model="newTaskDesc"
counter
:maxlength="255"
/>
</div>
</form>
</MDBModalBody>
<MDBModalFooter>
<MDBBtn
color="secondary"
@click="
{
resetInputs();
taskModal = false;
}
"
>Close</MDBBtn
>
<MDBBtn
color="primary"
@click="handleSaveChanges"
:disabled="!canSendData"
>{{ isEdited.edited ? "Save changes" : "Add task" }}</MDBBtn
>
</MDBModalFooter>
</MDBModal>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import {
MDBContainer,
MDBRow,
MDBCol,
MDBListGroup,
MDBListGroupItem,
MDBBtn,
MDBModal,
MDBModalTitle,
MDBModalHeader,
MDBModalBody,
MDBModalFooter,
MDBInput,
MDBIcon,
} from "mdb-vue-ui-kit";
import axios from "axios";
interface SingleTask {
_id: number;
name: string;
desc: string;
}
const taskList = ref<SingleTask[]>([]);
const taskModal = ref(false);
const newTaskName = ref("");
const newTaskDesc = ref("");
const isEdited = ref({ edited: false, value: -1 });
const API_URL = ref("");
const canSendData = computed(() => {
if (newTaskName.value.trim() === "" || newTaskDesc.value.trim() === "") {
return false;
}
return true;
});
const resetInputs = () => {
newTaskName.value = "";
newTaskDesc.value = "";
isEdited.value = { edited: false, value: -1 };
};
const handleSaveChanges = async () => {
if (!canSendData.value) {
return;
}
isEdited.value.edited
? updateTask(isEdited.value.value, newTaskName.value, newTaskDesc.value)
: createTask(newTaskName.value, newTaskDesc.value);
resetInputs();
taskModal.value = false;
};
const editModal = (task: SingleTask) => {
newTaskName.value = task.name;
newTaskDesc.value = task.desc;
isEdited.value = { edited: true, value: task._id };
taskModal.value = true;
};
const getTaskList = () => {
axios
.get(`${API_URL.value}tasks/`)
.then((res) => (taskList.value = res.data));
};
const createTask = (name: string, desc: string) => {
const data = { name, desc };
axios.post(`${API_URL.value}tasks/`, data).then(() => {
getTaskList();
});
};
const deleteTask = (id: number) => {
axios.delete(`${API_URL.value}tasks/${id}`).then(() => {
getTaskList();
});
};
const updateTask = (id: number, name: string, desc: string) => {
const data = { name, desc };
axios.put(`${API_URL.value}tasks/${id}`, data).then(() => {
getTaskList();
});
};
onMounted(() => {
API_URL.value = import.meta.env.VITE_API;
getTaskList();
});
</script>
Step 5
The app should be fully functional and should work correctly with backend
npm start
Optimization
If you want to further optimize your application please visit:
Backend features
Django:
This example was created with use of Django. Our app is connected to MySQL database and is ready to receive get, post, put and delete
requests.
Frontend features
MDB UI KIT:
To create the project we used our ui kit, with which we can build basic views very quickly.
Views and Layouts:
In this project we used the App.vue
file, created by the Vite tool in which we placed our vue
code. We have successfully integrated the backend with the MDB package and can send basic requests to backend Django application.