Django RestAPIs CRUD Example with MySQL Tutorial | Django Rest Framework ORM Tutorial – Post/Get/Put/Delete Examples

Django RestAPIs Tutorial - Post Get Put Delete Requests

In the tutorial, I introduce how to implement Django RestAPIs CRUD Example with MySQL database using Django Rest Framework with Post, Get, Put, Delete requests.

– I draw overview diagram architecture and explain details the flow of code and all the main blocks of Django project with MySQL database.
– I guide step by step how to setup and implement the Django project with Django Rest Framework and MySQL database.
– I create a testsuite with a number of integrative testcases with CRUD RestAPI requests from rest-client Postman to Django Server and save/retrieve data to MySQL database.

Related posts:


Overview Django RestAPIs CRUD Examples using Django Rest Framework

Youtube Guide – Debug Django RestAPIs CRUD Example with Django Rest Framework

Django Framework

Django is an extremely popular and fully featured server-side web framework, written in Python. Django helps eliminate repetitive tasks making the development process an easy and time saving experience. Some well known sites that use Django include Instagram, Disqus, Washington Times, Bitbucket and Mozilla.

Advantages of Django:

  • Object-Relational Mapping (ORM) Support – Django provides a bridge between the data model and the database engine,
  • Administration GUI − Django provides a nice ready-to-use user interface for administrative activities.
  • Development Environment − Django comes with a lightweight web server to facilitate end-to-end application development and testing.

Django supports the Model-View-Template (MVT) pattern.

Django MVT Pattern
Django MVT Pattern

Django takes care of the Controller part to control the interactions between the Model and View, leaving us with the template. The template is a HTML file mixed with Django Template Language (DTL).

Architecture of Django RestAPIs CRUD Workflow

Here is the architecture of Django RestAPIs CRUD Example:

Django RestAPIs Workflow
Django RestAPIs Workflow

– Django Application interacts with MySQL/PostgreSQL database via Model layers.
– The Views are simply Python functions that take web requests and return web responses.
– URLs are used to mapping each request with the corresponding views.

Overview Project Struture of Django RestAPIs CRUD Example

Django RestAPIs Tutorial - Project Structure
Django RestAPIs Tutorial – Project Structure

The Django RestAPIs project includes 2 folders:

  • djangoLoiZenAiRestAPIs is a main project folder
  • customers is an application folder

Goal

– Post a Customer:

Django RestAPIs Goal - Post a Customer Example
Django RestAPIs Goal – Post a Customer Example

– Get all Customers example:

Django RestAPIs Tutorial - Get All Customers Example
Django RestAPIs Tutorial – Get All Customers Example

– Put a Customer example:

Django RestAPI Tutorial - PUT a Customer
Django RestAPI Tutorial – PUT a Customer

– Delete a Customer:

Django RestAPI Tutorial - Delete a Customer
Django RestAPI Tutorial – Delete a Customer

– Check database’s records:

Django RestAPI Tutorial - List all records in dataase
Django RestAPI Tutorial – List all records in dataase

Practice

To prepare an environment for development, you need to install both Python, Django and a MySQL/PostgreSQL database.

– You can check python installed by cmd: python --version

C:\Users\USER>python --version
Python 3.8.3

– You can test your Django installation by running this command:
$ django-admin.py --version

C:\Users\USER>django-admin.py --version
3.0.8

Create a Django project

  • In Django, every web application you want to create is called a project
  • And a project is a sum of applications.
  • An application is a set of code files relying on the MVT pattern.

– Open a cmd and type the below command to create a djangoLoiZenAiRestAPIs project:

$ django-admin startproject djangoLoiZenAiRestAPIs

Now the project folder djangoLoiZenAiRestAPIs is created with the following structure:

djangoLoiZenAiRestAPIs/
   manage.py
   djangoLoiZenAiRestAPIs/
      __init__.py
      settings.py
      urls.py
      wsgi.py
  • manage.py is used to interact with your project via command line (start the development server, sync db…).
  • __init__.py is a python file that treats this folder as package.
  • settings.py is a project settings file.
  • urls.py defines all url links of your project and the function to call
  • wsgi.py is used when you deploy your project over WSGI

All setting of the Django project is in file djangoLoiZenAiRestAPIs/settings.py.

Check a debug option:

DEBUG = True

This option sets your project is in debug mode or not. Debug mode gives you more information about your project’s error. In the production live build, Never set it to ‘True’.

Install Django REST framework

Django REST framework works on top of Django and helps us to build RESTful Web Services flexibly. To install this package, run command:
pip install djangorestframework

Create Django Customer Application

As mention in above session, a Django project has a set of many applications. Each application is implemented with a specific purpose and can be reused into another project.

For creating a Customer application, we go to the project folder djangoLoiZenAiRestAPIs. Start the cmd:

$ python manage.py startapp customers

Django will create a “customers” folder with the application structure as below:

customers/
   __init__.py
   admin.py
   models.py
   tests.py
   views.py
  • __init__.py is used by python to handle this folder as a package.
  • admin.py is used to hepl us modify the app in the admin interface.
  • models.py is place to store all application models.
  • tests.py is a place to write unit tests.
  • views.py is where to implement application views.

Open customers/apps.py, we can see CustomersConfig class (subclass of the django.apps.AppConfig) that represents our Django app and its configuration:

from django.apps import AppConfig


class CustomersConfig(AppConfig):
    name = 'customers'

we need to register our customes application with our Django project djangoLoiZenAiRestAPIs by updating INSTALLED_APPS tuple in the settings.py file of Django project:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Django REST framework 
    'rest_framework',
    # Customers application 
    'customers.apps.CustomersConfig',
]

Create Customer model

A model class represents table or collection in our DB. Models are defined in the customers/models.py:

from django.db import models 
 
class Customer(models.Model):
    firstname = models.CharField(max_length=70, blank=False, default='')
    lastname = models.CharField(max_length=70, blank=False, default='')
    age = models.IntegerField(blank=False, default=1)
    address = models.CharField(max_length=70, blank=False, default='')
    copyrightby = models.CharField(max_length=70, blank=False, default='')

All Django models must inherit from django.db.models.Model. Customer class has 5 attributes (4 CharField and 1 Integer), those will be the table fields.

Serialize Customer Model

For serialization Python model object to JSON and deserialization Python object from JSON, We create a Serializer class for Customer instances:

– The CustomerSerializer class will inherit from rest_framework.serializers.ModelSerializer superclass.
ModelSerializer class automatically populates a set of default fields and default validators, we only need to specify the model class.

Now, under customers package, create serializers.py file:

from rest_framework import serializers 
from customers.models import Customer
 
class CustomerSerializer(serializers.ModelSerializer):
 
    class Meta:
        model = Customer
        fields = ('id',
                  'firstname',
                  'lastname',
                  'age',
                  'address',
                  'copyrightby')

Meta inner class declares 2 attributes:

  • model specifies the model related to the serializer
  • fields specifies a tuple of field names that we want to include in the serialization

Setup Database Configuration

Setup MySQL database environment

For working with MySQL database, we have to install Python MySQL Client to work with MySQL database.
In this tutorial, we use pymysql: pip install pymysql.

Once the installation is successful, import this module in djangoLoiZenAIRestApis/__init__.py:

import pymysql
pymysql.version_info = (1, 3, 13, "final", 0)
pymysql.install_as_MySQLdb()

– Configure again the database tuple in settings.py file:

DATABASES = {
   'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'loizenjavadb',
        'USER': 'root',
        'PASSWORD': '12345',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

Setup PostgreSQL database environment

In case, we want to work with PostgreSQL database, we have to install Python PostgreSQL client.
In the tutorial, we use psycopg2: pip install psycopg2

– Configure again the database tuple in settings.py file:

DATABASES = {
   'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'loizenjavadb',
        'USER': 'root',
        'PASSWORD': '12345',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}

Migrate Customer Model to database

Run following Python script:
python manage.py makemigrations customers

We can see output text:


Migrations for 'customers':
  customers\migrations\0001_initial.py
    - Create model Customer

It indicates that the customers/migrations/0001_initial.py file includes code to create Customer data model:

# Generated by Django 3.0.8 on 2020-07-15 15:43

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Customer',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('firstname', models.CharField(default='', max_length=70)),
                ('lastname', models.CharField(default='', max_length=70)),
                ('age', models.IntegerField(default=1)),
                ('address', models.CharField(default='', max_length=70)),
                ('copyrightby', models.CharField(default='', max_length=70)),
            ],
        ),
    ]

The generated code defines a subclass of the django.db.migrations.Migration. It has an operation for creating Customer model table. Call to migrations.CreateModel() method will create a table that allows the underlying database to persist the model.

Run the following Python script to apply the generated migration:
python manage.py migrate customers

The output text:


Operations to perform:
  Apply all migrations: customers
Running migrations:
  Applying customers.0001_initial... OK

Check MySQL Database, now we can see that a table for Customer model was generated and it’s named customers_customer:

Customers_customer tables schema
Customers_customer tables schema

Configure Django Admin Page

Django provides a ready-to-use user interface for administrative activities. To have it working you need to make sure some modules are imported in the INSTALLED_APPS and MIDDLEWARE_CLASSES tuples of the djangoLoiZenAiRestAPIs/settings.py file.

INSTALLED_APPS make sure you have:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Django REST framework 
    'rest_framework',
    # Customers application 
    'customers.apps.CustomersConfig',
    # CORSq
    'corsheaders',
]

– MIDDLEWARE_CLASSES:

MIDDLEWARE = [
    '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',
    # CORS
    'corsheaders.middleware.CorsMiddleware',  
    'django.middleware.common.CommonMiddleware',  
]

Before running Django server to access the Admin page, we need to initiate the database:
$ python manage.py migrate

Check MySQL database tables:

Django database tables
Django database tables

Use the below command to create a super-user to login Admin page:

$ python manage.py createsuperuser

Create super-user
Create super-user

Register admin URL in djangoLoiZenAiRestAPIs/urls.py file:


from django.contrib import admin
from django.urls import path

from django.conf.urls import url, include 
 
urlpatterns = [ 
    path('admin/', admin.site.urls),
]

Register Customer model in ./customers/admin.py file:

from django.contrib import admin

# Register your models here.
from customers.models import Customer

# Register your models here.
admin.site.register(Customer)

Testing Django Admin Page

Launch Django server by cmd:

python manage.py runserver

Go to Admin page by URL link http://localhost:8000/admin/:

Django Admin Page
Django Admin Page

Site Administration has 2 parts:

  • AUTHENTICATION AND AUTHORIZATION
  • CUSTOMERS

Authentication and Authorization has Groups and Users pages, where we can add, modify, delete, update a specific user.

Django administration User Page
Django administration User Page

Customers is a place to manipulate (create, get, update, delete) all entities of the Customers application.

Add a Entity from Django Administration page
Add a Entity from Django Administration page
Django Administration List All Customers
Django Administration List All Customers

Implement Django Views – Post/Get/Put/Delete requests

Django “view” is simply a Python function that takes a web request and returns a web response. This response can be the HTML contents of a Web page, or a redirect, or a 404 error, or an XML document, or an image … In the tutorial, we implement Django views that return JSON responses.

Implement Django Views
Implement Django Views

We create 3 Python function for Django views:

  • def customer_list(request) is used to POST a Customer entity, GET/DELETE all Customer entities per a request
  • def customer_detail(request, pk) is used to GET/PUT/DELETE a Customer via id key
  • def customer_list_age(request, age) is used to filter all Customers by age via a GET request

Django POST/GET/DELETE requests

In the ./customers/views.py file, I implements a Python function def customer_list(request) for POST/GET/DELETE Customer entities

@api_view(['GET', 'POST', 'DELETE'])
def customer_list(request)
Python code for the POST request

Here is a list of 4 steps we do to handle a Django POST request:

  • Parsing a body request then serializing it to transform the JSON data to a Python Object
    customer_data = JSONParser().parse(request)
    customer_serializer = CustomerSerializer(data=customer_data)
  • Save the serializing object to database:
    customer_serializer.save()
  • Return a JsonResponse object to a client with a status code
    JsonResponse(response, status=status.HTTP_201_CREATED)
  • If having any error or exception, return the JSON error object to client
    JsonResponse(error, status=status.HTTP_400_BAD_REQUEST) or
    JsonResponse(exceptionError, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

– Coding Example:

if request.method == 'POST':
try:
	customer_data = JSONParser().parse(request)
	customer_serializer = CustomerSerializer(data=customer_data)
	
	if customer_serializer.is_valid():
		customer_serializer.save()
		print(customer_serializer.data)
		response = {
		   'message': "Successfully Upload a Customer with id = %d" % customer_serializer.data.get('id'),
		   'customers': [customer_serializer.data],
		   'error': "" 
		}
		return JsonResponse(response, status=status.HTTP_201_CREATED)
	else:
		error = {
			'message':"Can Not upload successfully!",
			'customers':"[]",
			'error': customer_serializer.errors
		}
		return JsonResponse(error, status=status.HTTP_400_BAD_REQUEST)
except: 
	exceptionError = {
			'message': "Can Not upload successfully!",
			'customers': "[]",
			'error': "Having an exception!"
		}
	return JsonResponse(exceptionError, status=status.HTTP_500_INTERNAL_SERVER_ERROR);
Python code for the GET request

For getting all Customer entities from database with Django GET request, we do a list of 4 steps as following:

  • Get all Customer’ entities via Customer model class
  • Serialize a List of Customer Objects
  • Return a JsonResponse object with Python dictionary body and http status code
    JsonResponse(response, status=status.HTTP_200_OK);
  • If having any error or exception, just return a JsonResponse object with a building body for errors and a http status error code:
    JsonResponse(error, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
if request.method == 'GET':
	try:
	  customers = Customer.objects.all()
	  customers_serializer = CustomerSerializer(customers, many=True)

	  response = {
		 'message': "Get all Customers'Infos Successfully",
		 'customers': customers_serializer.data,
		 'error': ""
	  }
	  return JsonResponse(response, status=status.HTTP_200_OK);
	except: 
	  error = {
		'message': "Fail! -> can NOT get all the customers List. Please check again!",
		'customers': "[]",
		'error': "Error"
	  }
	  return JsonResponse(error, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Python code for the DELETE request

For deleting all entities from database, we just use a .all().delete() API function of django.db.models.Model class.

– Details example:

elif request.method == 'DELETE':
	try:
		Customer.objects.all().delete()
		return HttpResponse(status=status.HTTP_204_NO_CONTENT)
	except:
		exceptionError = {
				'message': "Can Not Deleted successfully!",
				'customers': "[]",
				'error': "Having an exception!"
			}
		return JsonResponse(exceptionError, status=status.HTTP_500_INTERNAL_SERVER_ERROR);

Django PUT request

In ./customers/views.py file, We define a view function customer_detail to do a PUT/GET/DELETE a Customer entity with a given id:

@api_view(['GET', 'PUT', 'DELETE'])
def customer_detail(request, pk)

For PUT/GET/DELETE a database entity with a given id, firstly we need to check the existing of an entity with the id. If having an DoesNotExist exception throws, we stop processing the request and return a JsonResponse object with a body is an exception’s error and a http status code NOT_FOUND:

try: 
	customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
	exceptionError = {
		'message': "Not found a Customer with id = %s!" % pk,
		'customers': "[]",
		'error': "404 Code - Not Found!"
	}
	return JsonResponse(exceptionError, status=status.HTTP_404_NOT_FOUND) 

For handing a PUT request, we do a list actions with 4 steps:

  • Parsing the request’s body object
    customer_data = JSONParser().parse(request)
  • De-serialize the above parsing data:
    customer_serializer = CustomerSerializer(customer, data=customer_data)
  • Store the object to database by .save() API function:
    customer_serializer.save()
  • Return a JsonResponse object with user-defined response:
    response = {
    	'message': "Successfully Update a Customer with id = %s" % pk,
    	'customers': [customer_serializer.data],
    	'error': ""
    }                
    return JsonResponse(response) 
    
  • If having any exception being throwed, we need to handle it and return an error with 404 status code:
    return JsonResponse(response, status=status.HTTP_400_BAD_REQUEST)
try:
	customer_data = JSONParser().parse(request)
	customer_serializer = CustomerSerializer(customer, data=customer_data)

	if customer_serializer.is_valid(): 
		customer_serializer.save()
		response = {
			'message': "Successfully Update a Customer with id = %s" % pk,
			'customers': [customer_serializer.data],
			'error': ""
		}                
		return JsonResponse(response) 

	response = {
			'message': "Fail to Update a Customer with id = %s" % pk,
			'customers': [customer_serializer.data],
			'error': customer_serializer.errors
		}
	return JsonResponse(response, status=status.HTTP_400_BAD_REQUEST) 

Here is the remain code in the view function def customer_detail(request, pk) for GET and DELETE request with a given id:

if request.method == 'GET':
	customer_serializer = CustomerSerializer(customer) 
	response = {
		'message': "Successfully get a Customer with id = %s" % pk,
		'customers': [customer_serializer.data],
		'error': ""
	}
	return JsonResponse(response, status=status.HTTP_200_OK);
	
	...
	
elif request.method == 'DELETE':
	print("Deleting a Customer with id=%s"%pk)
	customer.delete() 
	customer_serializer = CustomerSerializer(customer) 
	response = {
			'message': "Successfully Delete a Customer with id = %s" % pk,
			'customers': [customer_serializer.data],
			'error': ""
		}
	return JsonResponse(response)

Django filter requests

Now We continue define a Django GET RestAPI to filter all Customer entities with a given age as below code:

@api_view(['GET'])
def customer_list_age(request, age):
    try:
        customers = Customer.objects.filter(age=age)
        
        if request.method == 'GET': 
            customers_serializer = CustomerSerializer(customers, many=True)
            response = {
                'message': "Successfully filter all Customers with age = %s" % age,
                'customers': customers_serializer.data,
                'error': ""
            }
            return JsonResponse(response, safe=False)
            # In order to serialize objects, we must set 'safe=False'
    except:
        exceptionError = {
                'message': "Fail to get a Customer with age = %s" % age ,
                'customers': "[]",
                'error': "Raise an Exception!"
            }
        return JsonResponse(exceptionError, status=status.HTTP_500_INTERNAL_SERVER_ERROR);

We had used a function API filter(**kwargs) to filter all Customer entities from database that match the given lookup parameters customers_serializer = CustomerSerializer(customers, many=True).

Configure Django URLs

We define a set of Rest URL for Customers Application in file ./customers/urls.py:

from django.conf.urls import url 
from customers import views 
 
urlpatterns = [ 
    url(r'^customers/$', views.customer_list),
    url(r'^customers/(?P<pk>[0-9]+)$', views.customer_detail),
    url(r'^customers/age/(?P<age>[0-9]+)/$', views.customer_list_age),
]

We need include the Customer Application’s URL file to project’s urls.py file:

from django.contrib import admin
from django.urls import path

from django.conf.urls import url, include 
 
urlpatterns = [ 
    url(r'^', include('customers.urls')), 
    path('admin/', admin.site.urls),
]

Testing

Testcase 1 – Post a Customer to Django RestAPIs

– Post a Customer:

Testcase 1 - Django Post Request
Testcase 1 – Django Post Request

– Check database after posting:

Testcase 1 - Check database's records
Testcase 1 – Check database’s records

Testcase 2 – Get Customer’s request

– Get All Customers:

Testcase 2 - Get All Customers
Testcase 2 – Get All Customers

– Get a Customer by ID:

Testcase 2- get a Customer by ID
Testcase 2- get a Customer by ID

Testcase 3 – Update a Customer

Testcase 3 - Update a Customer
Testcase 3 – Update a Customer

Testcase 4 – Filter a Customer

Filter a customer with age = 46:

Testcase 4 - Filter a Customer by age
Testcase 4 – Filter a Customer by age

Testcase 5 – Delete a Customer

Testcase 5 - Delete a Customer by a given id = 3
Testcase 5 – Delete a Customer by a given id = 3

Sourcecode

Here is the clearly sourcecode of Django RestAPIs CRUD Example with MySQL and Django Rest Framework ORM:

django-LoiZenAiRestAPIs

– GITHUB Sourcecode:

DjangoRestAPIs

Leave a Reply

Your email address will not be published. Required fields are marked *