Getting up and running with the Django REST framework

In this blog, we’re going to go from a blank slate to a working Django REST API with full CRUD functionality. To keep things semi-simple, we’re going to use a single model called “tasks” with two attributes: “name” and “notes”. We will then migrate this model, create a route to it, and then finally setup an API serializer/view page. In the end, you’ll have something like this:

What you will need:

  • Python 3.x

Assumptions:

  • You are using MacOS or Ubuntu. (You’re welcome to try using Windows, however these commands may not line up)

First steps — Getting our environment in place.

Lets open our command terminal and locate a place we can store our project. I’m going to store this project in my “Documents” folder in a directory called “django_rest_blog_project”. You can use any directory name you like.

mkdir django_rest_blog_projectcd django_rest_blog_project

Inside this directory, lets create a python virtual environment.

python3 -m venv venv

Let’s activate our virtual environment

source venv/bin/activate

Before we start installing applications, let’s make sure our pip version is up to date:

pip install --upgrade pip

Now lets start installing the tools we’ll need.

Django

pip install Django

PostgreSQL

pip install psycopg2

Creating a project:

We’ll start off by creating a project. Think of the project as the “root” that encompasses the entire project.

django-admin startproject task_api

Creating an app:

Great. Now that we have a project, we’re going to add an app called ‘tasks’. Apps are one step down in the hierarchy in Django. To use an analogy: the project is the federal government and apps are like the states.

python manage.py startapp tasks

Registering the app and framework libraries

Our app is created, but for security reasons, Django doesn’t have access to it by default. To fix this, we’ll need to modify the settings.py file located in /task_api/

Once you have settings.py open, well need to add both our app and the REST framework to the INSTALLED_APPS list:

/task_api/settings.py

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'tasks',
]

Note the two bottom additions: “rest_framework” and “tasks”. Don’t go anywhere yet. We also need to wire up the database with PostgreSQL which is also in settings.py.

Configuring PostgreSQL

Further down in settings.py should be another list called “DATABASES”. Here we’ll point Django to your local PostgreSQL setup. Your attributes will vary here, but below is a common example:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': 'YOURSQLPASSWORD',
'HOST': '127.0.0.1',
'PORT': '5433',
}
}

Creating a model:

We’ve got a project. We’ve got an app. We’ve got a database engine. We can now start building out our model. For this, you’ll need to modify the /tasks/models.py file.

Here, we’ll build out our model with the two fields we mentioned before: “name” and “notes”.

/tasks/models.py

from django.db import models# Create your models here.
class Tasks(models.Model):
name = models.TextField(max_length=50)
notes = models.TextField(max_length=500)

Django database modeling is a complex topic, and there’s a ton you can do as far as what datatypes they can store. In this example, we’re keeping things simple with just a standalone model called “Tasks” with two attributes that hold plain text, (name and notes) We’re setting a max_length attribute as well since it’s a good security practice. (We don’t want hackers uploading gobs of data and breaking our server)

Register the model with the admin console.

One of the advantages of Django is that it has a built in admin console that can be very useful. In order for the admin console to know about our model though, we’ll need to register it.

Hopping over to our /tasks/admin.py, go ahead and add the following code:

/tasks/admin.py

from django.contrib import admin
from .models import Task
# Register your models here.
admin.site.register(Task)

Here, we’re importing the model we just created and then registering it.

Creating a superuser

In order to log into the admin console, you’ll need a superuser.

python manage.py createsuperuser

Follow the on-screen prompts to complete the process. We’ll use this later when testing.

Migrating your model.

Our model has been created and registered! Now lets add our model to the database. Bring up our command prompt again and type in the following:

from the root of project (look for manage.py)

python manage.py makemigrations
python manage.py migrate

If all goes well, you should see the following:

Assuming the migration was successful, we can start working on our URLs so users can access this data.

Creating URLs

Url’s can be a bit tricky. We need to instruct Django on where to send requests when a user does a fetch. (If you’re coming from rails, we would call this concept routes)

Here, we’d like a user be able to access task data by visiting http://server/tasks/

To keep things simple, we’re going to manage all of our routing in our project’s urls.py file. (/task_api/urls.py) You will see another urls.py in the app directory (/tasks/urls.py) but we’re not going to be using this for now. (In very large Django projects, the project urls.py routes to each application which then manages its own internal routes. Again, think Federal vs State governments. Here it adds too much unneeded complexity)

/task_api/urls.py

from rest_framework import routers
from tasks.views import TaskView
from django.contrib import admin
from django.conf.urls import url

router = routers.SimpleRouter()

router.register('tasks', TaskView)

urlpatterns = [
url('admin/', admin.site.urls),
]

urlpatterns += router.urls

There is a lot going on here, so we’ll break it down.

router = routers.SimpleRouter()

We’re using a library called “simple router” which is exactly that… it makes routing simple. This lets us create basic url strings that we can then register with the router and append to our URL patterns list just below. For example if we want users to be able to type in http://server/tasks/, we can create this using:

router.register('tasks', TaskView)

If you decide to create additional models, it’s just a matter of repeating this pattern, which makes things easy.

Creating the serializer and view:

With Django REST api’s, getting the actual data to the user involves two concepts: a serializer and a view.

Here we’re going to create a simple version of both in the views.py file located in the tasks app:

/tasks/views.py

from rest_framework import serializers
from rest_framework import viewsets
from .models import Task


class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ['name', 'notes']


class TaskView(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer

Above, we’re importing two libraries from the rest_framework: serializers, and viewsets. Since we also need access to our data, we’re importing our Task model. A serializer allows us to control which fields we want displayed to the user. In this case, we’re providing everything:

fields = ['id', 'name', 'notes']

Fun fact: a shorthand for this is

fields = '__all__'

Both will yield the same result.

Serializers can get very complex, and deserve their own blog article, but for now, we’re using a very basic example. A much more in-depth explanation can be found in the Django rest framework documentation.

The second class deals with the view. In the TaskView class, we’re defaulting to display all Task objects with:

queryset = Task.objects.all()

viewsets.ModelViewSet knows to look for queryset in the TaskView class when displaying view information. It also knows to look for serializer_class when serializing data. Both of these variables need to exist in order for a view class to work.

Testing:

At this point, our database, model, urls, serializers, and views should all be in place. We can test our server by running:

python manage.py runserver

By default, you can check to see if the model was created successfully by visiting: http://127.0.0.1:8000/admin/ and logging in with the super user you created earlier.

Lastly, you can check to see if your tasks api is online by visiting

http://127.0.0.1:8000/tasks/

If you see JSON data, congrats! You’ve successfully launched a Django REST api!