Introducing Django REST Framework
In the last four entries, we have been getting to know Django and its basic use. We want to use Django to create a good data source that responds to simple queries. We have seen how to get the responses in HTML. Since HTML is a structured language, we can kind-of consider that the mission is accomplished. But to serve data, a better way is to return JSON files. In this entry, we will get to know the Django REST framework that helps in creating RESTful applications, that is what we are seeking.
Actually, we could implement this functionality by using JSON templates instead of HTML. The resulting system would be quite simple, but not as flexible and bug-free as using a well established platform. We will reimplement our Simpsons quote search engine
The Django REST framework is centered around the concept of serialization, a representation of objects in a way that can be saved in a file or transmitted over a network connection without loss of information or functionality. In our case, we will translate the objects in the Django database into a JSON string. The REST framework provides serializers, classes that define how a model should be serialized, and class based views, that substitute the classic Django views and simplify RESTful applications.
The first step is installing the framework with pip install djangorestframework. Next, we must add it to our project as an additional application; so we edit the SQProject/settings.py file, and in the INSTALLED_APPS sections, we must add:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'SQapp', 'rest_framework', ]
the next step is to define a serializer for our SimpsonQuote model. For that, we create a new file SQapp/serializers.py with these contents:
from rest_framework import serializers from SQapp.models import SimpsonQuote class QuoteSerializer(serializers.ModelSerializer): class Meta: model = SimpsonQuote
This is the simplest form of serializer; it just uses a ModelSerializer, which copies each of the fields of the model set in its Meta class. Many more options are available, but we won’t cover them here.
Next, we create the class based view in SQapp/views.py. For that, we add the following lines to what is already present in the file:
from rest_framework.views import APIView from rest_framework.response import Response from SQapp.serializers import QuoteSerializer class QuoteSearchClass(APIView): def get(self, request): # First request return render(request, 'searchform.html') def post(self, request): # Second request searchterms = request.POST['terms'].split() if len(searchterms) >= 1: searchresults = SimpsonQuote.objects.filter(content__icontains = searchterms[0]) for additional_term in searchterms[1:]: searchresults = searchresults.filter(content__icontains = additional_term) if len(searchresults) > 0: serializer = QuoteSerializer(searchresults, many=True) return Response(serializer.data) else: return Response({'message':'No results found'}) else: return Response({'message':'Please enter some search terms'})
Let’s do a quick analysis of this code. We have a new class QuoteSearchClass that inherits from APIView and where we define two methods: get(), that processes GET requests and post(), that processes POST requests. We do not change the way we process GET requests by now. We just change what we return for POST requests; we use a Response object which we initialize with the appropriate contents. In the case of the results, we create a QuoteSerializer that contains one or more results and return its data to the clients. For the error messages, we use a standard dictionary. Finally, we must change where the URLs point in SQproject/urls.py to use this class:
from django.conf.urls import url from django.contrib import admin from HWapp.views import randomquote, quotesearch, QuoteSearchClass urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^randomquote/', randomquote), url(r'^search/', QuoteSearchClass.as_view()), ]
We will need to update the project by running python manage.py migrate, and then we can run the server and test the app. We will see that the results page changes a lot, showing an environment that contains the JSON strings of the results, among other things. This means that the basic system is working, but we have some more steps to go.
Let’s go back to what our final objective is; we want to have a RESTful application, that serves data to any application that uses that protocol. In this scenario, a search form does not make much sense. We must eliminate (or at least ignore) that form. It will be just a little bit more difficult to test the application, since we will have to use cURL or a similar tool. We still need to initiate the protocol with a GET request, in order to get a cookie for the CSRF middleware in the response, and, in the future, add the login function. To do this, we must execute cURL with the following parameters:
curl -c cookies.txt localhost:8000/search/
This will save the required cookies, and among them, a CSRF key that we will need to extract. We can then build our POST request:
curl -b cookies.txt -d "terms=&csrfmiddlewaretoken= " localhost:8000/search/
This will return us a JSON string with the contents of the search results. Theres a lot to clean up yet (for instance, removing the initial prompt altogether), but we can actually use this in a program written in any language. Summarizing, we have created an online API for our Simpsons quote database. We will refine this in the future.