Sign up with your email address to be the first to know about new products, VIP offers, blog features & more.

Creating a Rest API/Webservice with Django Rest Framework and MYSQL using Python 3

Introduction

Here you will see how to create a rest api using Django Rest Framework.

I chose to use Django Rest Framework because i am going to use this for a Machine Learning project in which i use Python as the default language, which is the language of Django.

The complete code for this project is in my github here: https://github.com/fernandorodriguespro/rest-api-django-drf-mysql

Preparation

Create the project directory e cd into it

mkdir project-name && cd project-name

 

Create a virtualenv to isolate our package dependencies locally, and activate the virtual environment

virtualenv -p python3 env && source env/bin/activate

 

Django Install

Install Django into the virtualenv

pip3 install django

 

Set up a new project and cd into it

# Note the trailing '.' character
django-admin.py startproject project . && cd project

 

Define a single application for this project

django-admin.py startapp appname && cd ..

 

Add the created App to INSTALLED_APPS in settings.py, using your favorite IDE

INSTALLED_APPS = [
    #...
    'project.appname'
]

 

Remove the default database engine that is automatically set for you. By default Django adds the SQLite, we don’t want that. Remove the definitions from DATABASES in settings.py. It should look like this, after you remove the default key:

DATABASES = {
}

 

Test if the App is working

python3 manage.py runserver

Go to http://localhost:8000/ to check if you see a Welcome page.

 

MySQL Install (on Mac)

For this Tutorial i will use MySQL, so we need to install it, on Mac using Homebrew you do this:

# this is a global install
brew install mysql

 

MySQL Setup on Django

Now install mysqlclient to the project

# this is an env install
pip3 install mysqlclient

On Mac i received a linker error telling that ld: library not found for -lssl, here is the solution:

LDFLAGS=-L/usr/local/opt/openssl/lib pip3 install mysqlclient # explicitly define the linker openssl path

 

Add the connection settings in settings.py, your config should look like this:

# project settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'dbname',
        'USER': 'root',
        'PASSWORD': '',
        'HOST': '127.0.0.1', # Or an IP Address that your DB is hosted on
        'PORT': '',
    },
}

 

Create the models that will be migrated to the database, more information on django model fields here https://docs.djangoproject.com/en/1.9/ref/models/fields/

# project/appname/models.py

from django.db import models

class University(models.Model):
    name = models.CharField(max_length=50)

    class Meta:
        verbose_name = "University"
        verbose_name_plural = "Universities"

    def __unicode__(self):
        return self.name

class Student(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    university = models.ForeignKey(University, on_delete=models.DO_NOTHING)

    class Meta:
        verbose_name = "Student"
        verbose_name_plural = "Students"

    def __unicode__(self):
        return '%s %s' % (self.first_name, self.last_name)

 

Generate these entities in the database

First create a set of rules.

python3 manage.py makemigrations appname

 

Then apply all the migrations

python3 manage.py migrate

 

Populate the Database

Django offers the Admin interface, a visual way to check and populate the database. To enable it add this to the app admin.py file.

from django.contrib import admin
from .models import University, Student

admin.site.register(University)
admin.site.register(Student)

 

Create the admin user

python3 manage.py createsuperuser

 

Check if the Admin interface is working here http://localhost:8000/admin/

 

Install Django REST Framework

Install it using PIP3

pip3 install djangorestframework

 

Declare it in INSTALED_APPS on settings.py

INSTALLED_APPS = [
    #...
    'rest_framework'
]

 

Write some model-based serializers (this process converts python objects into json and vice versa, called serialization/deserialization task). To do this, create a file named serializers.py in your appname, and then add the content below.

# appname/serializers.py, this file was created manually
from rest_framework import serializers
from .models import University, Student

class UniversitySerializer(serializers.ModelSerializer):
    class Meta:
        model = University
        fields = '__all__'

class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = '__all__'

More info here: http://www.django-rest-framework.org/api-guide/serializers/#modelserializer

 

Make a ViewSet (This is something amazing, lots of free added functionality  here in ModeViewSet code). It’s a full CRUD set.

# appname/views.py
from django.shortcuts import render

from rest_framework import viewsets
from .models import University, Student
from .serializers import UniversitySerializer, StudentSerializer

class StudentViewSet(viewsets.ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

class UniversityViewSet(viewsets.ModelViewSet):
    queryset = University.objects.all()
    serializer_class = UniversitySerializer

 

Define mappings (routes) from http request addresses to the views (controllers). Your project urls.py should look like this:

# project/urls.py
# Attach app-level urls to the general workflow

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

from django.conf import settings
from django.conf.urls import url, include

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('project.appname.urls')),
]

'''
if settings.DEBUG:
    from django.conf.urls.static import static
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

RAISES AN ERROR

File "/Users/fernandorodrigues/Documents/projects-angular/arin.ai/project/urls.py", line 18, in 
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
File "/Users/fernandorodrigues/Documents/projects-angular/arin.ai/env/lib/python3.6/site-packages/django/conf/urls/static.py", line 21, in static
raise ImproperlyConfigured("Empty static prefix not permitted")
django.core.exceptions.ImproperlyConfigured: Empty static prefix not permitted
'''

Add app “child” routes to appname/urls.py

# create this file
# rerouting all requests that have ‘api’ in the url to the apps.core.urls

from django.conf.urls import url
from rest_framework import routers
from project.appname.views import StudentViewSet, UniversityViewSet

router = routers.DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'universities', UniversityViewSet)

urlpatterns = router.urls

 

Check if the service is functional accessing http://localhost:8000/api/universities/

Here everything must be working fine!!

 

Creating a Custom View with APIView

In the above example, we created two ViewSets: StudentViewSet and UniversityViewSet. These two classes inherits viewsets.ModelViewSet, which gives us, for free, an entire set of CRUD operations. But sometimes we don’t need all this, we may want to have full control of the View for something more simple.

Here is how to add a custom View for an application. Add this to the views.py of the app.

from rest_framework.views import APIView, Response

class CustomView(APIView):
    def get(self, request, format=None):
        return Response("Some Get Response")

    def post(self, request, format=None):
        return Response("Some Post Response")

Create a route for this View

# create this file
# rerouting all requests that have ‘api’ in the url to the&nbsp;<code>apps.core.urls</code>

from django.conf.urls import url
from rest_framework import routers
from project.appname.views import StudentViewSet, UniversityViewSet, CustomView

router = routers.DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'universities', UniversityViewSet)

urlpatterns = [
    url(r'customview', CustomView.as_view()),
]

urlpatterns += router.urls

Go to http://localhost:8000/api/customview to check if the route is working.

Generating Documentation for this API with Django Rest Swagger

First install the wheel

pip3 install django-rest-swagger

 

Declare this app in INSTALED_APPS

# project/settings.py

INSTALLED_APPS = [
    #...
    'rest_framework_swagger'
]

 

Expose it at routing under api/docs

# appname/urls.py
from django.conf.urls import url
from rest_framework import routers
from project.arin.views import StudentViewSet, UniversityViewSet
from rest_framework_swagger.views import get_swagger_view

router = routers.DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'universities', UniversityViewSet)

schema_view = get_swagger_view(title='Pastebin API')

urlpatterns = [
    url(r'customview', CustomView.as_view()),
    url(r'^docs/', schema_view),
]

urlpatterns += router.urls

 

Check if the service is functional accessing http://localhost:8000/api/docs/

 

Sources:

http://www.django-rest-framework.org/

https://tests4geeks.com/django-rest-framework-tutorial/

https://docs.djangoproject.com/en/1.9/ref/models/fields/

https://marcgibbons.com/django-rest-swagger/

6 Responses
  • Stu
    May 24, 2018

    Fantastic guide. Just what I needed. Thankyou.

  • Clancy Emanuel
    September 12, 2018

    This was awesome, thanks. Two minor issues on Windows 10 using VS Code:

    1. Django wouldn’t install on Windows. Fixed with “pip install –only-binary :all: mysqlclient” (courtesy of kaya’s answer: https://stackoverflow.com/questions/26866147/mysql-python-install-error-cannot-open-include-file-config-win-h)
    2. When making the ViewSets for the models, PyLint complained about not being able to import .serializers because the classes did not have an “object” member. Use this link to fix: https://stackoverflow.com/questions/45135263/class-has-no-objects-member

    Also, you could consider saying something about inspectdb for legacy databases.

    • Clancy Emanuel
      September 18, 2018

      #1 I meant to say mysqlclient would not install.

  • Aguilared
    December 5, 2018

    Brother!!! Excelent…

  • Aguilared
    December 6, 2018

    MySQL Setup on Django in Windows 10,
    pip3 install mysqlclient. This didnt work for me.
    Use:
    pip install –only-binary :all: mysqlclient
    and it went all through, no need for MS Visual C++ 14 Build tools and stuff
    Note: for now this doesnt work with Python3.7, i also had to downgrade to Python 3.6.5

  • André
    May 5, 2019

    Great tutorial thank you.

What do you think?

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