Django 3 is released with full async support! In this 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 4 for styling.
You'll learn how to:
Implement CRUD operations,
Configure and access a MySQL database,
Create Django views, templates and urls,
Style the UI with Bootstrap 4
Django 3 Features
Django 3 comes with many new features such as:
MariaDB support: Django now officially supports MariaDB 10.1+. You can use MariaDB via the MySQL backend,
ASGI support for async programming,
Django 3.0 provides support for running as an ASGI application, making Django fully async-capable
Exclusion constraints on PostgreSQL: Django 3.0 adds a new ExclusionConstraint class which adds exclusion constraints on PostgreSQL, etc.
Let's start with the prerequisites for this tutorial. In order to follow the tutorial step by step, you'll need a few requirements, such as:
django-admin.py
and manage.py
),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!
In this step, we'll create a mysql database for storing our application data.
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!
In this step, we'll initialize a new virtual environment for installing our 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.
In this step, we'll install django 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-3.0.2
is installed.
You will also need to install the mysql client for Python using pip
:
$ pip install mysqlclient
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
You'll get a similar output:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
This simply applies a set of builtin django migrations to create some necessary database tables or the working of django.
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 insll django-widget-tweaks
Next, open the settings.py
file and add the application to the installed apps:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'widget_tweaks'
]
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:
Username (leave blank to use 'ahmed'):
Email address: [email protected]
Password:
Password (again):
Superuser created successfully.
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 = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'widget_tweaks',
'crudapp'
]
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 these model, you need to create migrations using the following command:
$ python manage.py makemigrations
You should get a similar output:
crudapp/migrations/0001_initial.py
- Create model Contact
Next, you need to migrate your database using the following command:
$ python manage.py migrate
You should get a similar output:
Applying crudapp.0001_initial... OK
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.
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})
Open the settings.py
file and add os.path.join(BASE_DIR, 'templates')
to the TEMPLATES
array:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
This will tell django 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 3 CRUD Example - LaravelCode</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" 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://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"
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/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 %}
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'),
]
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.
In this Django 3 tutorial, we have initialized a new Django project, created and migrated a MySQL database, and built a simple CRUD interface.
Hi, My name is Harsukh Makwana. i have been work with many programming language like php, python, javascript, node, react, anguler, etc.. since last 5 year. if you have any issue or want me hire then contact me on [email protected]
phpMyAdmin Automatic Logout Time
phpMyAdmin is open-source web based appl...Laravel 8 - Create Contact in ZOHO Crm Tutorial Example
In this article, I will share with you h...Node.js MySQL Create Database into Database Server
In the previous article, we have seen ho...How to install VLC media player in Windows, MacOS and Linux
VLC is a free and open source cross-plat...How to zip and unzip files from Terminal in Linux
Zip is the most common feature to compre...