Django 5 Tutorial & CRUD Example with MySQL and Bootstrap
In this django 5 tutorial, we'll see by example how to create a CRUD application from scratch and step by step. We'll see how to configure a MySQL database, enable the admin interface, and create the django views.
We'll be using Bootstrap for styling.
You'll learn how to:
- Implement CRUD operations with django 5,
- Configure and access a MySQL database,
- Create django 5 views, templates and urls,
- Style the UI with Bootstrap
Prerequisites
Let's start with the prerequisites for this django 5 tutorial. In order to follow the tutorial step by step, you'll need a few requirements, such as:
- Basic knowledge of Python,
- Working knowledge of Django (
django-admin.py
andmanage.py
), - A recent version of Python 3 installed on your system,
- MySQL database installed on your system.
We will be using pip
and venv
which are bundled as modules in recent versions of Python so you don't actually need to install them unless you are working with old versions.
If you are ready, lets go started!
Django 5 Tutorial, Step 1 - Creating a MySQL Database
In this step, we'll create a mysql database for storing our application data of our django 5 example.
Open a new command-line interface and run the mysql
client as follows:
$ mysql -u root -p
You'll be prompted for your MySQL password, enter it and press Enter.
Next, create a database using the following SQL statement:
mysql> create database mydb;
We now have an empty mysql database for our django 5 example!
Django 5 Tutorial, Step 2 - Initializing a New Virtual Environment
In this step, we'll initialize a new virtual environment for installing our django 5 project packages in separation of the system-wide packages.
Head back to your command-line interface and run the following command:
$ python3 -m venv .env
Next, activate your virtual environment using the following command:
$ source .env/bin/activate
At this point of our tutorial, we've a mysql database for persisting data and created a virtual environment for installing the project packages.
Django 5 Tutorial, Step 3 - Installing Django and MySQL Client
In this step, we'll install django 5 and mysql client from PyPI using pip
in our activated virtual environment.
Head back to your command-line interface and run the following command to install the django package:
$ pip install django
At the time of writing this tutorial, django-5.0.6
is installed.
You will also need to install the mysql client for Python using pip
:
$ pip install mysqlclient
Django 5 Tutorial, Step 4 - Initializing a New Project
In this step, we'll initialize a new django project using the django-admin
.
Head back to your command-line interface and run the following command:
$ django-admin startproject djangoCrudExample
Next, open the settings.py
file and update the database settings to configure the mydb
database:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb',
'USER': 'root',
'PASSWORD': '<YOUR_DB_PASSWORD>',
'HOST': 'localhost',
'PORT': '3306',
}
}
Next, migrate the database using the following commands:
$ cd djangoCrudExample
$ python3 manage.py migrate
This simply applies a set of built in django 5 migrations to create some necessary database tables for the working of django.
Django 5 Tutorial, Step 5 - Installing django-widget-tweaks
In this step, we'll install django-widget-tweaks
in our virtual environment. Head back to your command-line interface and run the following command:
$ pip install django-widget-tweaks
Next, open the settings.py
file and add the application to the installed apps:
INSTALLED_APPS = [
[...]
'widget_tweaks'
]
Django 5 Tutorial, Step 6 - Creating an Admin User
In this step, we'll create an admin user that will allow us to access the admin interface of our app using the following command:
$ python manage.py createsuperuser
Provide the desired username, email and password when prompted.
Django 5 Tutorial, Step 7 - Creating a Django Application
In this step, we'll create a django application.
Head back to your command-line interface, and run the following command:
$ python manage.py startapp crudapp
Next, you need to add it in the settings.py
file as follows:
INSTALLED_APPS = [
[...]
'crudapp'
]
Django 5 Tutorial, Step 8 - Creating the Model(s)
In this step. we'll create the database model for storing contacts. Open the crudapp/models.py
file and add the following code:
from django.db import models
class Contact(models.Model):
firstName = models.CharField("First name", max_length=255, blank = True, null = True)
lastName = models.CharField("Last name", max_length=255, blank = True, null = True)
email = models.EmailField()
phone = models.CharField(max_length=20, blank = True, null = True)
address = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
createdAt = models.DateTimeField("Created At", auto_now_add=True)
def __str__(self):
return self.firstName
After creating this model, you need to create migrations using the following command:
$ python manage.py makemigrations
Next, you need to migrate your database using the following command:
$ python manage.py migrate
Django 5 Tutorial, Step 9 - Creating a Form
In this step, we'll create a form for creating a contact. In the crudapp
folder, create a forms.py
file and add the following code:
from django import forms
from .models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = "__all__"
We import the Contact model from the models.py
file. We created a class called ContactForm
, subclassing Django’s ModelForms from the django.forms
package and specifying the model we want to use. We also specified that we will be using all fields in the Contact
model. This will make it possible for us to display those fields in our templates.
Django 5 Tutorial, Step 10 - Creating the Views
In this step, we'll create the views for performing the CRUD operations. Open the crudapp/views.py
file and add:
from django.shortcuts import render, redirect, get_object_or_404
from .models import Contact
from .forms import ContactForm
from django.views.generic import ListView, DetailView
Next, add:
class IndexView(ListView):
template_name = 'crudapp/index.html'
context_object_name = 'contact_list'
def get_queryset(self):
return Contact.objects.all()
class ContactDetailView(DetailView):
model = Contact
template_name = 'crudapp/contact-detail.html'
Next, add:
def create(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
form = ContactForm()
return render(request,'crudapp/create.html',{'form': form})
def edit(request, pk, template_name='crudapp/edit.html'):
contact = get_object_or_404(Contact, pk=pk)
form = ContactForm(request.POST or None, instance=post)
if form.is_valid():
form.save()
return redirect('index')
return render(request, template_name, {'form':form})
def delete(request, pk, template_name='crudapp/confirm_delete.html'):
contact = get_object_or_404(Contact, pk=pk)
if request.method=='POST':
contact.delete()
return redirect('index')
return render(request, template_name, {'object':contact})
Django 5 Tutorial, Step 11 - Creating Templates
Open the settings.py
file and add os.path.join(BASE_DIR, 'templates')
to the DIRS
array:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
[...]
},
]
This will tell django 5 to look for the templates in the templates
folder. Next, inside the crudapp
folder create a templates
folder:
$ mkdir templates
Next, inside the templates
folder, create the following files:
-
base.html
-
confirm_delete.html
-
edit.html
-
index.html
-
create.html
-
contact-detail.html
By running the following commands from the root of your project:
$ mkdir templates
$ cd templates
$ mkdir crudapp
$ touch crudapp/base.html
$ touch crudapp/confirm_delete.html
$ touch crudapp/edit.html
$ touch crudapp/index.html
$ touch crudapp/create.html
$ touch crudapp/contact-detail.html
Open the crudapp/templates/base.html
file and the add:
<!DOCTYPE html>
<html>
<head>
<title>Django 5 CRUD Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
</head>
<body>
{% block content %}
{% endblock %}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
</body>
</html>
Next, open the crudapp/templates/index.html
file and the add:
{% extends 'crudapp/base.html' %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-md-1 col-xs-1 col-sm-1"></div>
<div class="col-md-10 col-xs-10 col-sm-10">
<h3 class="round3" style="text-align:center;">Contacts</h3>
</div>
<div class="col-md-1 col-xs-1 col-sm-1"></div>
</div>
<div class="row">
<div class="col-md-10 col-xs-10 col-sm-10"></div>
<div class="col-md-2 col-xs-1 col-sm-1">
<br />
<a href="{% url 'create' %}">
<button type="button" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span>
</button>
</a>
</div>
</div>
<br />
{% for contact in contact_list %}
<div class="row">
<div class="col-md-1 col-xs-1 col-sm-1"></div>
<div class="col-md-7 col-xs-7 col-sm-7">
<ul class="list-group">
<li class="list-group-item ">
<a href="{% url 'detail' contact.pk %}"> {{ contact.firstName }} {{contact.lastName}} </a> <span class="badge"></span>
</li>
</ul>
<br>
</div>
<div class="col-md-1 col-xs-1 col-sm-1">
<a href="{% url 'detail' contact.pk %}">
<button type="button" class="btn btn-info">
<span class="glyphicon glyphicon-open"></span>
</button>
</a>
</div>
<div class="col-md-1">
<a href="{% url 'edit' contact.pk %}">
<button type="button" class="btn btn-info">
<span class="glyphicon glyphicon-pencil"></span>
</button>
</a>
</div>
<div class="col-md-1">
<a href="{% url 'delete' contact.pk %}">
<button type="button" class="btn btn-danger">
<span class="glyphicon glyphicon-trash"></span>
</button>
</a>
</div>
<div class="col-md-1 col-xs-1 col-sm-1"></div>
</div>
{% endfor %}
</div>
{% endblock %}
Next, open the crudapp/templates/create.html
file and the add:
{% load widget_tweaks %}
<!DOCTYPE html>
<html>
<head>
<title>Posts</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<style type="text/css">
<style>
</style>
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-1 col-xs-1 col-sm-1"></div>
<div class="col-md-10 col-xs-10 col-sm-10 ">
<br />
<h6 style="text-align:center;">
<font color="red"> All fields are required</font>
</h6>
</div>
<div class="col-md-1 col-xs-1 col-sm-1">
</div>
</div>
<div class="row">
<div class="col-md-1 col-xs-1 col-sm-1"></div>
<div class="col-md-10 col-xs-10 col-sm-10">
<form method="post" novalidate>
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class="form-control" %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">post</button>
</form>
<br>
</div>
<div class="col-md-1 col-xs-1 col-sm-1"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
crossorigin="anonymous"></script>
</body>
</html>
Next, open the crudapp/templates/edit.html
file and the add:
{% load widget_tweaks %}
<!DOCTYPE html>
<html>
<head>
<title>Edit Contact</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<style type="text/css">
<style>
</style>
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-1 col-xs-1 col-sm-1"></div>
<div class="col-md-10 col-xs-10 col-sm-10 ">
<br />
<h6 style="text-align:center;">
<font color="red"> All fields are required</font>
</h6>
</div>
<div class="col-md-1 col-xs-1 col-sm-1">
</div>
</div>
<div class="row">
<div class="col-md-1 col-xs-1 col-sm-1"></div>
<div class="col-md-10 col-xs-10 col-sm-10">
<form method="post" novalidate>
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class="form-control" %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">submit</button>
</form>
<br>
</div>
<div class="col-md-1 col-xs-1 col-sm-1"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>
Next, open the crudapp/templates/confirm_delete.html
file and the add:
{% extends 'crudapp/base.html' %}
{% block content %}
<div class="container">
<div class="row"></div>
<br />
<div class="row">
<div class="col-md-2 col-xs-2 col-sm-2"></div>
<div class="col-md-10 col-xs-10 col-sm-10">
<form method="post">
{% csrf_token %}
<div class="form-row">
<div class="alert alert-warning">
Are you sure you want to delete {{ object }}?
</div>
</div>
<button type="submit" class="btn btn-danger">
<span class="glyphicon glyphicon-trash"></span>
</button>
</form>
</div>
</div>
</div>
{% endblock %}
Django 5 Tutorial, Step 12 - Creating URLs
In this step, we'll create the urls to access our CRUD views.
Go to the urls.py
file and update it as follows:
from django.contrib import admin
from django.urls import path
from crudapp import views
urlpatterns = [
path('admin/', admin.site.urls),
path('contacts/', views.IndexView.as_view(), name='index'),
path('contacts/<int:pk>/', views.ContactDetailView.as_view(), name='detail'),
path('contacts/edit/<int:pk>/', views.edit, name='edit'),
path('contacts/create/', views.create, name='create'),
path('contacts/delete/<int:pk>/', views.delete, name='delete'),
]
Django 5 Tutorial, Step 11 - Running the Local Development Server
In this step, we'll run the local development server for playing with our app without deploying it to the web.
Head back to your command-line interface and run the following command:
$ python manage.py runserver
Next, go to the http://localhost:8000/
address with a web browser.
Conclusion
In this django 5 tutorial, we have initialized a new django project, created and migrated a MySQL database, and built a simple CRUD interface.
-
Date: