Introduction to API with Django
Today I’ll talk about how to setup a basic API with Django. In the process, I’ll give step-by-step instructions of how to create a simple To Do app. You can see an example of this done on this repository. Also we’ll go over the basics of how to protect the endpoints through the use of a JWT token. Let’s get started!
Setting Up
Before you start make sure you have python and pip installed (we are using python 3).
To handle our dependencies in an isolated manner we are using virtual environments. To set it up on Ubuntu first install virtualenv module:
python3 -m pip install --user virtualenv
Then run the command below. This will create a folder that will hold all the dependencies for that environment. We’ll create ours in a folder named python-environments located in our home folder but you can place it wherever you like.
> cd ~/python-environments> python3 -m venv django-api
Now, you need to activate this virtual environment by running the command below. This command will vary according to where you choose to create the your environment. In our case:
source ~/python-environments/django-api/bin/activate
Once you activate the environment you can access the python command directly without having to type python3 and any modules you install using pip will be placed within the folder we created.
Installing Django
Next we’ll setup Django and the admin panel. The first step is to install the Django package through pip. With our venv activated run the command:
python -m pip install Django
If all goes well you’ll get the version number when running the command:
python -m django --version
Creating a Project
To create a blank Django project run the command below. It will create a folder with the name you defined for the project and all the necessary files. We’ll call our project djangoapi. Next cd into the folder you just created.
> django-admin startproject djangoapi> cd djangoapi
Creating a Module for the App
Within this folder there will another folder with same name [djangoapi]. This is the main module and contains some key configuration files we’ll get to in a moment. You could create your logic withing this folder, however it’s a common practice to create one or more modules for your application in order to keep things organized. Run the command below to create a module called todo where we’ll put the logic for our todo app.
> python manage.py startapp todo
Here the contents of our project so far.
Next we need to tell Django about the new module we just created. We do this through configuring the value of INSTALLED_APPS in the settings file located in the main module. This file contains all the settings for the project. Add the the value todo.apps.TodoConfig to the installed apps settings like so:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'todo.apps.TodoConfig']
Notice that this string refers to the TodoConfig class in the file djangoapi/todo/apps.py.
Running the Application
A few more things before we can run the project. Django automatically manages the database so we don’t need to create any tables manually. Run the command below to prepare the database for use. For this tutorial we are using a basic file based database that comes pre-configured with Django. However, these steps are same regardless of whether you use Postgres or any other solution.
> python manage.py migrate
Also, to access the admin panel generated by Django you must create an admin user. This can be easily done by running the command below and following the prompts.
> python manage.py createsuperuser
All done! Run this command to run the project:
> python manage.py runserver
Now access http://127.0.0.1:8000/admin in your browser and login with credentials of the superuser you’ve created. You’ll be greeted by the following screen:
This is the famous Django admin panel, a module that automatically generates an admin panel based on the models you define. This can be highly customized and is often used by staff members to manage content of an application. Django already comes with models for users and groups that we can use in our API. Once we add our own models they’ll also be listed here.
Creating our Model
We’ll create a model for our to do item. We’ll place it in the models file in the module we created for our app (djangoapi/todo/models.py).
from django.db import modelsclass Todo(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) name = models.CharField(max_length=20) completed = models.BooleanField(default=False)
The attributes created_at and updated_at are timestamps automatically managed by Django. Django will use these files to create and query the database. You may create as many models as you’d like and would probably need to split this file into a file for each model as they grow in size. Django Models are very powerful and can handle many different cases and their documentation is a great source of information.
In order for our new models to be picked up by the admin panel we need to adjust the file djangoapi/todo/admin.py. In this file we can configure how our module will behave and look in the admin panel. Here is the content of that file after the adjustment:
from django.contrib import adminfrom .models import Todoadmin.site.register(Todo)
Lastly, we need to tell Django to adjust the database to accommodate the new models:
> python manage.py makemigrations> python manage.py migrate
All done! Our model is now fully configured. It is now listed in the admin panel and we can now create, edit and remove to do items directly from here.
Configuring the API
We’ll use a module called Django rest framework to make things a little easier. First we need to install the necessary packages.
> pip install djangorestframework> pip install markdown> pip install django-filter
Next, adjust the settings file to include rest_framework as an installed app like so:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'todo.apps.TodoConfig', 'rest_framework']
Creating the Endpoints
For our example API we will create three endpoints: (a) one to create a to do item; (b) one to edit a to do and (c) one to view a to do item. The url’s for these endpoints will be:
- POST /api/todos- GET /api/todos/<id>- PUT /api/todos/<id>
The endpoints with POST and PUT will accept two body parameters: (a) the name of the to do item and (b) whether or not it is completed.
We’ll created the logic for our endpoints in the views file within our module (djangoapi/todo/views.py). We’ll extend the APIView class from the rest_framework module and create a function for each of the methods we’d like to implement. To implement our three endpoints our views would look like this:
from django.http import JsonResponsefrom rest_framework.views import APIViewfrom .models import Todoclass TodosView(APIView): def post(self, request): todo_name = request.data.get('name', '') completed = request.data.get('completed', '') todo = Todo( name=todo_name, completed=completed.lower() in ['True', 'true'] ) todo.save() return JsonResponse({ "id": todo.id, "name": todo.name, "completed": todo.completed }) def get(self, request, id): todo = Todo.objects.get(id=id) return JsonResponse({ "id": todo.id, "name": todo.name, "completed": todo.completed }) def put(self, request, id): todo_name = request.data.get('name', '') completed = request.data.get('completed', '') todo = Todo.objects.get(id=id) todo.completed = completed.lower() in ['True', 'true'] todo.name = todo_name todo.save() return JsonResponse({ "id": todo.id, "name": todo.name, "completed": todo.completed })
Notice that any data passing in the body of the request will be available in the object request.data. Parameters passed as segments of the url are passed in as arguments.
Configuring the Url
The last step is to map the routes and the views we have created. To do this, we edit the urls file in the main module (located at: djangoapi/djangoapi/urls.py). To configure the three endpoints we need for our APP our url file would look like this:
from django.contrib import adminfrom django.urls import pathfrom todo.views import TodosViewurlpatterns = [ path('admin/', admin.site.urls), path("api/todos", TodosView.as_view()), path("api/todos/<int:id>", TodosView.as_view()),]
Now Django knows that when it gets requests to “api/todos” and “api/todos/<id>” it will let our views handle the process.
Security
Let’s quickly add a layer of security to our endpoints otherwise anyone can access them. For that will use this module that integrates with Django rest framework. To install it:
> pip install djangorestframework-simplejwt
Now for Django rest to work properly with this module we need to add the following to the settings file:
REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": [ "rest_framework.permissions.IsAuthenticated", ], "DEFAULT_AUTHENTICATION_CLASSES": ["rest_framework_simplejwt.authentication.JWTAuthentication"] }
The first part (DEFAULT_PERMISSION_CLASSES) defines a rule where every endpoint will return 401 (unauthorized) unless the user is authenticated. The second property (DEFAULT_AUTHENTICATION_CLASSES) defines the module just installed as the one responsible for for authentication. From here on out, the requests will only be accepted if the contain an Authorization header with a proper token.
Generating the Token
The Simple JWT module already provides an endpoint to generate a token. To get this to work we have to make a adjustment to the url file. Here’s how it should look:
from django.contrib import adminfrom django.urls import pathfrom rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView,)from todo.views import TodosViewurlpatterns = [ path('admin/', admin.site.urls), path("api/todos", TodosView.as_view()), path("api/todos/<int:id>", TodosView.as_view()), path('api/token', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/token/refresh', TokenRefreshView.as_view(), name='token_refresh')]
Now, if you make a request to ‘http://127.0.0.1:8000/api/token’ passing in the credentials of the admin user you created in the body of the request you’ll get a refresh and a access token.
Now add a header in the format ‘Authorization: Bearer <ACCESS_TOKEN>’ to your requests and we are all set! Requests without this token will be denied. This will work with tokens generated with credentials of new users created in the admin panel as well!
One more thing, while inside the root folder run the command below to generate a list of python dependencies.
> pip freeze > requirements.txt
And that concludes the end of this post! I hope you found this to be useful 😎. In case you would like to get in touch: linkedin.
THE BLOG
News, lessons, and content from our companies and projects.
41% of small businesses that employ people are operated by women.
We’ve been talking to several startups in the past two weeks! This is a curated list of the top 5 based on the analysis made by our models using the data we collected. This is as fresh as ...
Porto Seguro Challenge – 2nd Place Solution
We are pleased to announce that we got second place in the Porto Seguro Challenge, a competition organized by the largest insurance company in Brazil. Porto Seguro challenged us to build an ...
Predicting Reading Level of Texts – A Kaggle NLP Competition
Introduction: One of the main fields of AI is Natural Language Processing and its applications in the real world. Here on Amalgam.ai we are building different models to solve some of the problems ...
Porto Seguro Challenge
Introduction: In the modern world the competition for marketing space is fierce, nowadays every company that wants the slight advantage needs AI to select the best customers and increase the ROI ...
Sales Development Representative
At Exponential Ventures, we’re working to solve big problems with exponential technologies such as Artificial Intelligence, Quantum Computing, Digital Fabrication, Human-Machine ...
Exponential Hiring Process
The hiring process is a fundamental part of any company, it is the first contact of the professional with the culture and a great display of how things work internally. At Exponential Ventures it ...
Exponential Ventures annonce l’acquisition de PyJobs, FrontJobs et RecrutaDev
Fondé en 2017, PyJobs est devenu l’un des sites d’emploi les plus populaires du Brésil pour la communauté Python. Malgré sa croissance agressive au cours de la dernière année, ...
Exponential Ventures announces the acquisition of PyJobs, FrontJobs, and RecrutaDev
Founded in 2017, PyJobs has become one of Brazil’s most popular job boards for the Python community. Despite its aggressive growth in the past year, PyJobs retained its community-oriented ...
Sales Executive
At Exponential Ventures, we’re working to solve big problems with exponential technologies such as Artificial Intelligence, Quantum Computing, Digital Fabrication, Human-Machine ...
What is a Startup Studio?
Spoiler: it is NOT an Incubator or Accelerator I have probably interviewed a few hundred professionals in my career as an Entrepreneur. After breaking the ice, one of the first things I do is ask ...
Social Media
At Exponential Ventures, we’re working to solve big problems with exponential technologies such as Artificial Intelligence, Quantum Computing, Digital Fabrication, Human-Machine ...
Hunting for Unicorns
Everybody loves unicorns, right? But perhaps no one loves them more than tech companies. When hiring for a professional, we have an ideal vision of who we are looking for. A professional with X ...
Stay In The Loop!
Receive updates and news about XNV and our child companies. Don't worry, we don't SPAM. Ever.