Django REST Framework Tutorial

If you are working on a single-page application and you want it to have some persistence, it’s a really good idea to have a REST api. This way you’ll be able to store your domain’s entities in the database. In this article, you will learn how to create a basic application with Django and Django REST framework. You can use this as a starting point, and then it’s quite easy to extend this project with different pluggable Django applications.

You can find a repository here and demo here. The animation below shows the automatically generated html interface of the api created in this tutorial:

ezgif.com-crop

Make a project from a template

Use the code below to create an environment for further development.


$ mkdir drf-demo; cd drf-demo 
$ virtualenv .env 
$ pip install "Django >= 1.9, < 1.10" 
$ django-admin startproject project --template=https://github.com/ambivalentno/django-skeleton/archive/master.zip 
$ mkdir log $ mkdir project/db

Now your environment is fully functional.

Next, start your development server with the following:

$ python project/manage.py runserver

Finally, go to http://localhost:8000/. You will see a “Welcome, Django” message.

Define some models

Here we want to model students that go to a university. So, let’s first define entity classes and their attributes. Every university has a name; and every student has a first name, last name and attends a single university (many-to-one relationship). To see a list of available fields you can go to the Django manual for model fields.

Listing of project/apps/core/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)

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

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

Each Model here is related to a table in the database. As we don’t have these tables in the database yet, let’s create a rule to make them (in Django these rules are called migrations):

python project/manage.py makemigrations core

Now to apply them, do this:

python project/manage.py migrate core

You will see a lot of SQL queries logged to the console, and that’s absolutely fine. Now you have a database structure defined and we are ready to put some data in it.

Enable the admin interface and populate the database

Django’s admin interface offers a visually convenient way to discover and edit database data. To enable it, add this to the project/apps/core/admin.py:

Listing of project/apps/core/admin.py

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

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

Next, create an admin user (comand-line dialogue omitted, as it’s quite obvious):

python project/manage.py createsuperuser

Go to the admin url (ensure your development server is up):

You can add universities here and students here.

Congratulations! Without writing much code at all, go take a look at your brilliant and free functionality.

Recommendation

If your company is hiring a Python developer, check out this Python test prepared by our professionals. It will allow you to identify the best talents very easily!

Django REST framework-based api

Obviously, you cannot plug in anything unless you install it, so let’s install Django REST framework (or DRF) with pip:

$ pip install djangorestframework

Next, you should add ‘rest_framework’ to the INSTALLED_APPS at the project/conf/base.py so that it’s available for Django process.

Write some model-based serializers

To perform HTTP-based interaction we have to define rules to convert Django models (python objects) to the json strings and vice versa. This is a serialization/deserialization task. So, let’s define some model-based serializers:

Listing of project/apps/core/serializers.py

from rest_framework import serializers
from .models import University, Student

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

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

Of course, you can manually define your own serializers. As a reference, you can use DRF’s documentation or even some performance-oriented serializers.

Make a quick viewset

A viewset is a set of views (controllers in traditional MVC terminology). If you take a look at the ModelViewSet code you’ll see that there’s a lot of functionality automatically added there. You are able to create, view, edit and delete objects in your system (and database). It’s a full CRUD set with http as the interface protocol. Let’s configure two viewsets for our classes:

Listing of project/apps/core/views.py

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

Now we need to expose this logic to the outer space, which is done via url routers: we have to define mappings from http request addresses to the views (controllers).

To attach app-level urls to the general workflow – edit project/urls.py:

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('apps.core.urls', namespace='core')),
]

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)

Here we are rerouting all requests that have ‘api’ in the url to the apps.core.urls. Here’s a “child” url router, where

Listing of project/apps/core/urls.py

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

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

urlpatterns = router.urls

At this moment, you’ve got a working api. Let’s check it out!

Look at the browsable api

Go to the http://localhost:8000/api (demo url http://drf-demo.herokuapp.com/api) where you will see the browsable api:

rsz_screen_api_html

Next, go to http://localhost:8000/api/universities/ (demo link http://drf-demo.herokuapp.com/api/universities/) where you will see it’s possible to create new universities via POST requests with a simple form submission.

In case you want to view raw JSON – you can go to http://localhost:8000/api/universities/?format=json (demo link http://drf-demo.herokuapp.com/api/universities/?format=json). For students, it’s the same: http://localhost:8000/api/students/ (demo link http://drf-demo.herokuapp.com/api/students/)

Generate and read automatic documentation with django-rest-swagger

We’ve already installed one Django application, via pip. Now install Django-rest-swagger and add it to the INSTALLED_APPS (‘rest_framework_swagger’). To expose it at the url routing level, edit core/urls.py this way:

from django.conf.urls import url, include
from rest_framework import routers
from core.views import StudentViewSet, UniversityViewSet

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

urlpatterns = [
    url(r'^docs/', include('rest_framework_swagger.urls')),
]
urlpatterns += router.urls

As you can see here, we’ve used rest_framework_swagger to merge the api’s urls from the router and urls. You can check if it works at http://localhost:8000/api/docs/:

rsz_swagger

This way you’re able to view the definitions of DELETE, PUT and PATCH commands differently from the default DRF browsable api. Also, you may find the “Try it” button convenient.

Django REST Framework Tutorial: Step by Step Guide with Demo and Source CodeClick To Tweet

Summary

I hope this article helps you set up a REST api for your project. Remember, you can easily extend it, and if it’s hard for you – please, contact us.

Author
Yuri Kriachko is head of a Python/Django company, 7WebPages.

Coding skills assessment

If you're looking to hire software engineers and want to ensure that you only interview qualified candidates, we've created coding tests that can significantly simplify your hiring process:

20 Shares

  14 Comments

  1. Derek   •  

    Thanks for a useful tutorial. All fine up to the last part with Django swagger. Then I get this error:

    Traceback:
    File “/home/derek/.virtualenvs/drf/local/lib/python2.7/site-packages/django/core/handlers/base.py” in get_response
    119. resolver_match = resolver.resolve(request.path_info)
    File “/home/derek/.virtualenvs/drf/local/lib/python2.7/site-packages/django/core/urlresolvers.py” in resolve
    365. for pattern in self.url_patterns:
    File “/home/derek/.virtualenvs/drf/local/lib/python2.7/site-packages/django/core/urlresolvers.py” in url_patterns
    401. patterns = getattr(self.urlconf_module, “urlpatterns”, self.urlconf_module)
    File “/home/derek/.virtualenvs/drf/local/lib/python2.7/site-packages/django/core/urlresolvers.py” in urlconf_module
    395. self._urlconf_module = import_module(self.urlconf_name)
    File “/usr/lib/python2.7/importlib/__init__.py” in import_module
    37. __import__(name)
    File “/home/derek/dev/drf/project/urls.py” in
    7. url(r’^api/’, include(‘apps.core.urls’, namespace=’core’)),
    File “/home/derek/.virtualenvs/drf/local/lib/python2.7/site-packages/django/conf/urls/__init__.py” in include
    33. urlconf_module = import_module(urlconf_module)
    File “/usr/lib/python2.7/importlib/__init__.py” in import_module
    37. __import__(name)
    File “/home/derek/dev/drf/project/apps/core/urls.py” in
    11. url(r’^docs/’, include(‘rest_framework_swagger.urls’)),
    File “/home/derek/.virtualenvs/drf/local/lib/python2.7/site-packages/django/conf/urls/__init__.py” in include
    33. urlconf_module = import_module(urlconf_module)
    File “/usr/lib/python2.7/importlib/__init__.py” in import_module
    37. __import__(name)

    Exception Type: ImportError at /api/docs/
    Exception Value: No module named urls

    • sahi   •  

      Did you find a solution?

    • Anindya Sundar Manna   •  

      I solved it by changing the project/apps/core/urls.py to:

      from django.conf.urls import url, include
      from rest_framework import routers
      from core.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=’API Docs’)

      urlpatterns = [
      url(r’^docs/’, schema_view)
      ]
      urlpatterns += router.urls

    • Edi Santoso   •  

      Hi

      I think it’s been a long time, but if it is useful. You can use django-rest-swagger==0.3.5 instead of the latest version, It’s will solve your problem 🙂

    • wisani   •  

      you are using the latest swagger module,

      use,
      `from rest_framework_swagger.views import get_swagger_view

      urlpatterns = [
      url(r’^$’, get_swagger_view())
      ]
      `

      instead.

  2. arpit   •  

    Hi derek send your yourApp/urls.py file to examine the error

  3. Shubhanshu   •  

    Hi
    Thanks for the tutorial

    I want to do something like when i click on url of a particular university then i want it to show a list of urls of all the students enrolled in that.

    Simply i want to add a new field of ‘students’ in university model which will contain all urls of students enrolled in that.

    Can you please me how can i do that?

  4. fgf   •  

    ddd

  5. titty fuck   •  

    Please let me know if you’re looking for
    a article author for your blog. You have some really good posts and I believe I would be a good asset.

    If you ever want to take some of the load off, I’d really like to
    write some content for your blog in exchange for a link back
    to mine. Please blast me an email if interested.
    Regards!

  6. Daniel Aidoo   •  

    `from rest_framework_swagger.views import get_swagger_view

    urlpatterns = [
    url(r’^$’, get_swagger_view())
    ]
    `

    serializer.py
    model=Student #depending on how you named it
    fields=’__all__’

    model=University #depending on how you named it
    fields=’__all__’

  7. Deepak Chawla   •  

    getting this error

    __init__() takes exactly 1 argument (2 given)

  8. Nirav Rathod   •  

    USE jquery autoscroll to last added record

  9. shrikant   •  

    Thanks for a useful tutorial.

Leave a Reply

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