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:
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:
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/:
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 TweetSummary
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:
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
Did you find a solution?
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
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 🙂
you are using the latest swagger module,
use,
`from rest_framework_swagger.views import get_swagger_view
urlpatterns = [
url(r’^$’, get_swagger_view())
]
`
instead.
Hi derek send your yourApp/urls.py file to examine the error
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?
ddd
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!
`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__’
getting this error
__init__() takes exactly 1 argument (2 given)
USE jquery autoscroll to last added record
Please help me sort this problem
https://stackoverflow.com/questions/50367739/rest-framework-3-7-with-django-2-0-post-method-does-not-working-in-api-document?noredirect=1#comment87755771_50367739
Thanks for a useful tutorial.