In this series i’m challenging myself to create an API with a different language/framework each day to review some of the basics as well as to write a series of easy-to-follow tutorials for each API. We started off with Ruby on Rails yesterday and today we’ll be creating an API with Django’s rest-framework. As usual, all of today’s code can be found here.
As usual, before we begin, we need to install some dependencies. To get started, follow the instructions here (I highly recommend this blog as this was the one that I used when I first started learning web-development with Django).
Just like Node.js’ NPM and Rails’ RubyGem ecosystem, Python has its pip ecosystem and many packages can be easily installed using the
pip install PACKAGENAMEHERE command. Once Django is installed, install Django’s restful API framework via
pip install djangorestframework . Once installed, navigate to your desired directory and initiate a new Django project via
django-admin startproject PROJECTNAMEHERE .
Each “component” or “feature” in a Django is called an app; i.e. if you’re building a personal website, a blog might be an app that is a part of the project and a portfolio might be another app. Now that we have our project created, navigate into the project and create an app via
python manage.py startapp APPNAMEHERE .
Now that we have scaffolded a project and an app within it, the only piece of configuration left is to navigate to the
settings.py file within the subdirectory that has the same name as the name of the project (this is the “heart” of this app) and make the following changes:
- Include ‘rest_framework’ and ‘APPNAME.apps.APPNAMEConfig’ within the INSTALLED_APPS array. In the above screenshot, we named our app “blog” and hence we had to include ‘blog.apps.BlogConfig’ to let the main Django program know that these apps and packages are a part of our Django project.
- For our API to work in production, we need to take care of Cross-Origin-Resource-Sharing (CORS) . For this to work, we first have to run
pip install django-cors-headers, a package dedicated to controlling CORS configurations for Django applications.
- After installing
‘corsheaders’under the INSTALLED_APPS array just as before. Then, include
‘corsheaders.middleware.CorsMiddleware’under MIDDLEWARE as high up as possible. Finally, include
CORS_ORIGIN_ALLOW_ALL = Trueat the very end of
settings.py. We’ve allowed Django to permit CORS for all domains, but if you would like to customize permissions such that only specific domains can have access to the API, refer to this documentation.
Whew! We’re finally done with all the configurations here and all that is left is creating the model and setting up the endpoints. Now, for the purpose of this guide, let’s say that the app that we’ve had created is called “blog” and now let’s navigate to
blog/models.py and include the following
from django.db import models
# Create your models here.
title = models.TextField()
content = models.TextField()
Just as Rails, data are represented as models in Django. In our example, we’ve created a Post model that has 2 attributes, namely title and content. And just as Rails, each attribute needs to be specified its type. In this case, both title and content are TextFields, and there are other default Django model attribute types such as CharField. The
__str__ method is just the python way of specifying what to show when a user “prints” our an object, in this case, we want each object to be identified by its title.
Now, one of my favorite features from Django is its default admin panel. Instead of having to first create endpoints to
POST data, Django’s admin panel allows users to create Create, Read, Update or Delete (CRUD — restful actions) data and act as an intuitive interface to communicate with the database.
In order to access the admin panel to create some mock data just as we seeded our database in Rails yesterday, let’s first register our model into the admin panel so that we can manipulate it via the interface later. Navigate to the
admin.py file and include the following:
from django.contrib import admin
# Register your models here.
from .models import Post
And just as Rails, with the addition / modification of every model, we need to make migrations and migrate them. Thus, run
python manage.py makemigrations and
python manage.py migrate . Then, we will need to create an admin account to sign in to the admin panel. Let’s create one via
python manage.py createsuperuser and just follow its instructions in the terminal to create the account.
Now let’s spin up the development server via
python manage.py runserver and navigate to http://localhost:8000/admin . Login as requested and you should see the following screen.
At the bottom, you’ll see that our “blog” app is now showing and that the “post” model is showing as well. Click into it and you can start adding mock data as such.
Now that we have some mock data in our database, the final piece of the puzzle is to serialize the data and to create an endpoint to output these data. But what exactly does serialize mean? Serialization is simply the process of turning model objects (data) into JSON data that clients can consume.
Now, let’s create a
serializers.py file in the blog directory and include the following:
from rest_framework import serializers
from .models import Post
model = Post
fields = ('title', 'content')
Let’s break down this code. Our PostSerializer (it can be named anything, really) extends django’s rest_framework’s serializers.ModelSerializer class and that we need to add some Meta data to describe what content we are serializing. We indicate that the data that we are serializing is based on the Post model and that the fields that we are interested in are the
Let’s navigate to blog/views.py file and add the following:
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Post
from .serializers import PostSerializer
def get(self, request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
This block of code may seem confusing at first but let’s break it down together. Firstly, we import a series of packages and then create a “View”. Unlike most MVC frameworks like Rails, Django’s View-layer refers to the Controller in traditional MVC structures. You can read all about the controversy and decision here. The View layer in Django controls what kind of data is fetched and returns, and since we are only interested in making a
GET only API for the sake of this simple tutorial, we only fill in the method for
get(self, request) . So we first fetch all the Post objects via
Post.objects.all() and then we serialize it using the serializer that we’d created earlier, passing in the list of data as well as a specification
many=True to indicate that we are providing it with multiple data so that it should return us with a list. We finally return the data.
The final part of this is to create a route. So navigate to the project’s main directory and open its
settings.py file and add the following:
from django.conf.urls import url
from django.contrib import admin
from rest_framework.urlpatterns import format_suffix_patterns
from blog import views
urlpatterns = [
urlpatterns = format_suffix_patterns(urlpatterns)
This should only be slightly different from the default urlpatterns provided. We first import
format_suffix_patterns so that our endpoints will be RESTFUL. We then create a
posts/ route which we indicate that returns the blog-app’s views’ serialized-data.
We’re all set now and all we have to do is start the server again with
python manage.py runserver and hit up http://localhost:8000/posts and we should see the following JSON data.
Congratulations for making it through this tutorial and hope you’ve enjoyed it. Django is very easy to learn for beginners and I highly recommending this tutorial if you are new to web-development and programming in general. Python is a relatively easy-to-learn language and Django has some easy interfaces to interact with. Tomorrow, we’ll learn another Python-based framework, Flask. Stay tuned!