This tutorial is out of date and no longer maintained.
Code without tests is broken as designed. — Jacob Kaplan-Moss
In software development, testing is paramount. So why should I do it, you ask?
The best way to do code testing is by using Test-Driven Development (TDD).
This is how it works:
Being a fan of best practices, we are going to use TDD to create a bucketlist API. The API will have CRUD (Create, Read, Update, Delete) and authentication capabilities. Let’s get to it then!
The aim of this article is to help you learn awesome stuff while creating new things. We’ll be creating a bucket list API. If you haven’t heard about the term bucket list, it is a list of all the goals you want to achieve, dreams you want to fulfill, and life experiences you desire to experience before you die (or hit the bucket). This API should therefore help us to create and manage our bucketlists.
To be on the same page, the API should have the ability to:
Other complementary functionalities that will come later will be:
If you haven’t done any Django, Check out Building your first Django application. It’s an excellent resource for beginners.
Now that we know about a bucketlist, here’s a bit about the tools we’ll use to create its app.
Django Rest Framework (or simply DRF) is a powerful module for building web APIs. It’s very easy to build model-backed APIs that have authentication policies and are browsable.
For DRF to work, you must have:
Create and cd into your project folder. You can call the folder anything you like.
Then, create a virtual environment to isolate our code from the rest of the system.
The -p switch tells virtualenv the path to the python version you want to use. Ensure that you put the correct python installation path after the -p switch. venv
is your environment. Even though you can name your environment anything, it’s considered best practice to simply name it venv
or env
.
Activate your virtual environment by doing this:
You will see a prompt with the environment name (i.e., (venv)
). It means the environment is now active. Now we’re ready to install our requirements inside our environment.
Inside the projects folder, install Django using pip
If you lack pip in your system, simply do:
Since we need to keep track of our requirements, we’ll create a requirements.txt
file.
And add the installed requirements into the text file using pip freeze
Then finally, create a Django project.
We should now have a folder with the name djangorest
created. Feel free to give it any other name.
The folder structure should look like this:
djangorest
├─djangorest
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Using pip, install DRF
For our app to use DRF, we’ll have to add rest_framework
into our settings.py
. Let’s go right ahead and do that.
In Django, we can create multiple apps that integrate to form one application. An app in Django is simply a python package with a bunch of files including the __init__.py
file.
First, cd
into the djangorest directory on your terminal. We do this so that we can access the manage.py
file. Then create the app as follows:
The startapp
command creates a new app. Our app is called api
. It will hold our API logic. So far, you should have a folder named api
alongside the djangorest
app. To integrate our api
app with the djangorest
main app, we’ll have to add it to our djangorest settings.py
. Let’s go right ahead and do that.
We’d want to create the models first. But we have no tests written. We’ll therefore write some tests in the tests.py folder of our API app.
The code above imports the test case from django.test. The test case has a single test that tests whether the model can create a bucketlist with a name.
We need to create a blank model class. This is done in our models.py
Running the test is super easy with Django. We’ll use the test command as follows:
You should see a bunch of errors all over the screen. Don’t worry about it. It’s because we haven’t written our model fields and updated our database yet. Django uses SQlite as its default database so we’ll use it for now. Also, we don’t have to write a single SQL statement when creating the models. Django handles all that for us. In the models.py
we’ll define fields that will represent the table fields in our database.
Migrations are Django’s way of propagating changes you make to your models (like adding a field, deleting a model, etc.) into your database schema.
Now that we have a rich model in place, we need to tell the database to create the relevant schema.
In your console, run this:
This creates a new migration based on the changes we’ve made to our model.
Then, apply the migrations to your DB by doing this:
When you run the tests, you should see something like this:
The tests have passed! This means that we can proceed to write the serializers for our app
Serializers serialize and deserialize data. So what’s all this about, you ask?
Serializing is changing the data from complex querysets from the DB to a form of data we can understand, like JSON or XML. Deserializing is reverting this process after validating the data we want to save to the DB.
The ModelSerializer
class lets you automatically create a Serializer class with fields that correspond to the Model fields. This reduces our lines of code significantly.
Create a file called serializers.py
inside the API directory.
Let’s write some code in it:
We’ll first write the view’s tests. Writing tests seems daunting at first. However, it’s easy to know what to test when you know what to implement.
In our situation, we want to create views that will handle the following:
Based on the above functionality, we know what to test. We’ll use them as a guide.
Let’s take the first case. If we want to test whether the API will create a bucketlist successfully, we’ll write the following code in tests.py
:
This test fails when we run it. This is ok. It happens so because we haven’t implemented the views and URLs for handling the POST request.
Let’s go ahead and implement them! On views.py
, write the following code:
The ListCreateAPIView is a generic view that provides GET
(list all) and POST
method handlers
Notice we specified the queryset
and serializer_class
attributes. We also declare a perform_create
method that aids in saving a new bucketlist once posted.
For it to be complete, we’ll specify URLs as endpoints for consuming our API. Think of URLs as an interface to the outside world. If someone wants to interact with our web API, they’ll have to use our URL.
Create a urls.py
file on the API directory. This is where we define our URL patterns.
The format_suffix_pattern
allows us to specify the data format (raw JSON or even HTML) when we use the URLs. It appends the format to be used for every URL in the pattern.
Finally, we add a URL to the main app’s urls.py
file so that it points to our API app. We will have to include the api.urls
we just declared above into the main app urlpatterns
.
Go to the djangorest
folder and add the following to the urls.py
:
We’ll run our server the Django way with the runserver
command:
You should see this output on your console
That means everything is running smoothly.
Enter the server-specified URL (http://127.0.0.1:8000/bucketlists
) in your browser. And viola – It works!
Go ahead and write a bucketlist and click the post button to confirm whether our API works.
You should see something like this:
We’ll write three more tests to cater for GET
, PUT
and DELETE
requests. We’ll wrap them as follows:
If we run these tests, they should fail. Let’s fix that.
It’s time we complete the API with a PUT
and DELETE
method handlers.
We’ll define a view class for this. On the views.py
file, add the following code:
RetrieveUpdateDestroyAPIView is a generic view that provides GET
(one), PUT
, PATCH
, and DELETE
method handlers.
Finally, we create this new URL to be associated with our DetailsView.
Enter the specified URL (http://127.0.0.1:8000/bucketlists/1/
) in your browser. And voila! – It works! You can now edit the existing bucketlist.
Phew! Congratulations for making it to the end of this article – You are awesome!
In Part 2 of the Series, we’ll delve into adding users, integrating authorization and authentication, documenting the API, and adding more refined tests.
Want to dig deeper? Feel free to read more of DRF’s Official Documentation.
And if you’re new to Django, I find Django For Beginners excellent.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!