4.53 out of 5
511 reviews on Udemy

Build a Backend REST API with Python & Django – Advanced

Create an advanced REST API with Python, Django REST Framework and Docker using Test Driven Development (TDD)
Mark Winterbottom
2,845 students enrolled
English [Auto-generated]
Setting up a local development server with Docker
Writing a Python project using Test Driven Development
Building a REST API with advanced features such as uploading and viewing images
Creating a backend that can be used a base for your future projects or MVP
Hands on experience applying best practice principles such as PEP-8 and unit tests
Configure Travis-CI to automate code checks

Welcome to the advanced course on how to Build a Backend REST API using Python, Django, Django REST Framework, Docker, Travis CI, Postgres and Test Driven Development!

Whether you’re a freelance programmer, tech entrepreneur, or just starting out building backends – this course will help lay the foundation of your knowledge base and give you the tools to advance your skills with some of the most in-demand programming languages today.

APIs are the unsung heroes behind the technologies that we all love and use religiously.

One of the most critical components for any tech-based business is an API. So knowing how to create an API from start to finish is a vital skill to have as a developer. You cannot build a successful app without a backend REST API!

In this course I’ll show you how to build an advanced API that handles creating and updating user profiles, changing passwords, creating objects, uploading images, filtering and searching objects, and more.

The best way to learn anything is to do it. So the practical application of the course — the project that you’ll build along side me — is an API. A recipe API, to be specific.

You will learn how to build an advanced recipe API that allows you to upload and store some of your favourite recipes from photos and the web.

You’ll learn how to create objects i.e. recipes with titles, price points, cooking times, ingredients and tags like “comfort food”, “vegan” or “dessert”. Think of it as a virtual recipe box.

By the end of this course you will have built a fully functioning REST API that can handle:

  • User authentication

  • Creating objects

  • Filtering and sorting objects

  • Uploading and viewing images

You’ll also learn, in detail how to:

  • Setup a project with Docker and Docker-Compose

  • Configure Travis-CI to automatically run linting and unit tests

  • Write unit tests using the Django Test Framework

  • Apply best practice principles including Test Driven Development  

  • Handle uploading media files with Django

  • Customize the Django admin

  • Configure a Postgres database

This course has one singular focus: To teach you how to create an advanced API from start to finish using best practice principles and Test Driven Development.

This course is NOT FOR YOU:

  • If you’re looking for a course to build an API, a front end, and deployment

  • If you’re looking to build 10 different apps in one course

  • If you want to learn lots of different technologies and approaches to app development in general

This is a hands-on course, with a bit of theory and lots of opportunities to test your knowledge.

The content is challenging but rewarding. Ready for it? Let’s dive in!


Welcome to Build a Backend API with Django REST Framework - Advanced
Intro to the course
Course structure
How to get the most out of this course
How to get help

Technologies used in this course

Django REST Framework
What is test driven development?

Installation and setup

System setup
Windows 10 Home Workaround

Create new project

Setup new GitHub project

Setup a new project using GitHub and clone to our local machine.

Add Dockerfile

Create a new Dockerfile that we can use to build the image for our project.

Configure Docker Compose

Configure docker compose to run our project.

Create Django project

Create a new Django project using our docker compose file.

Setup automation

Enable Travis-CI for project

Login to Travis-CI and enable our project for automation.

Create Travis-CI configuration file

Create a configuration file that tells Travis-CI how to run our unit tests and linting.


Test your Travis-CI knowledge

Introduction to test driven development (TDD)

Writing a simple unit test

Write a very simple unit test to demonstrate the process of unit testing code using Django.

Writing a unit test with TDD

Write another very simple unit test, but this time we will follow the Test Driven Development (TDD) method.

Django Unit Tests

Test your knowledge on Django Unit Tests

Configure Django custom user model

Create core app

Use the Django management script to create a new app within our project. The app will be called 'core' and it will be used to hold all code that is central to our project (such as database models and the admin page).

Add tests for custom user model

Here we will create a custom user model for our project. The custom user model will replace Django's built in user model. The purpose of customising the model is to support handling registration and authentication using an email instead of username.

Implement custom user model

Implement the user model to make the tests pass.

Normalize email addresses

Next we will implement a change to our custom user manager that ensures emails are normalized. Normalizing the email means ensuring the domain part is all lowercase.

Add validation for email field

Here we will add an extra validation step to our create_user function, so it will raise a validation error if a blank or null email field is passed in. We do this so a correct error message is displayed when using this function.

Add support for creating superusers

Now we will add support for creating superusers using the create_superuser function on our custom user manager. The create_superuser function is used by the Django createsuperuser management command, so it's required for creating admin using the CLI, which we will be doing later in the course.

Django custom user model

Test your knowledge on the Django custom user model

Setup Django admin

Add tests for listing users in Django admin

Now we need to configure our Django admin to work with our custom user model. To do this, we need to make some modifications to the fields that Django displays in the default Django admin. In this video we setup the tests to test that our Django admin is working correctly.

Modify Django admin to list our custom user model

Now we will modify the Django admin to support listing users from our custom user model. This should make the tests from the previous video pass successfully.

Modify Django admin to support changing user model

Here we modify the Django admin to support changing the custom user model. We start by adding a test to ensure the 'user change page' loads successfully, then we implement the feature by modifying the fieldsets of the default Django UserAdmin class.

Modify Django admin to support creating users

Finally we can modify our Django admin to support creating new users. We start by testing the create user page, and end by making the necessary modifications to the add_fieldsets variable in our UserAdmin class.

Setting up database

Add postgres to docker compose

Here we will prepare our docker-compose.yml for running PostgreSQL Database 10 as our application database. In this video we start the setup by setting some environment variables for authentication with the database, and also adding our db service.

Add postgres support to Dockerfile

Before our docker container will support connecting to PostgreSQL, we need to make a few minor modifications. First we will add the psycopg2 package to our requirements.txt file, then we will update our Dockerfile to support installing and using the client for our application.

Configure database in Django

Now we can configure our database within the Django settings.py file. We will do this by updating the DATABASES settings and pulling in some environment variables.

Waiting for postgres to start

Mocking with unittests
Add tests for wait_for_db command

A common issue when using PostgreSQL with Django is that the application starts before the database. This causes it to fail with an OperationalError saying that the database is unavailable. To get around this, we will create a management command which we can use to delay starting our app until the database is up. We start by adding unit tests for our command. The unit tests will ensure the command works as expected when the database is and is not available.

Add wait_for_db command

Now we have our tests failing, we can go ahead and make them pass by creating our wait_for_db command.

Make docker compose wait for db

Finally we can update our docker-compose.yml file to run our wait_for_db management command before starting our app. While we are doing that, we will also add migrate to run our migrations when we start our docker container.

Test in browser

Finally we can update our docker-compose.yml file to run our wait_for_db management command before starting our app. While we are doing that, we will also add migrate to run our migrations when we start our docker container.


Test your knowledge on mocking

Create user management endpoints

Create users app

Next we are going to add our user management endpoints to our app. This will allow us to manage the users by performing tasks such as creating users, updating users, generating authentication tokens and changing the users password. We will start by creating a new app called 'user' which will contain all of our user code.

Add tests for create user API

Now we have our app, we can go ahead and create our user API. We start by adding some tests that validate creating a user, attempting to create a user with a duplicate email and creating a user with a password less than five characters.

Add create user API

Now we will make our tests pass by implementing our user API. For this, we need to create a Serializer to handle converting our user object from Python to JSON (and vice versa). Then we will create a View that handles creating users, and finally we will wire it up to a URL to make it accessible.

Add tests for creating a new token

Next we can move on to adding a create token API which will be used for authenticating users in future APIs. We start by adding some tests for creating a token, trying to create a token with invalid credentials, creating a token for users that don't exist and creating a token with a missing field.

Add create token API

Next we update our code to make our tests pass by implementing the AuthTokenSerializer and ObtainAuthToken view. We then add the URL for our endpoint and ensure it works by running our tests. At the end of the video, we will test our code in the browser to ensure it works.

Add tests for manage user endpoint

The last endpoint we need to add for our user management API is the manage user endpoint. This will allow users to manage their account by changing their password and updating various fields.

Add manage user endpoint

Next we will add the manage user endpoint. This endpoint will allow the user to update their profile or change their password. We will start by creating a view to handle the request, and re-use the UserSerializer we created previously. Finally, we will connect our view to a URL, run our tests and test in the browser.

Create tags endpoint

Create recipe app

In this section we will create our recipe app. The recipe app will be responsible for handling anything related to recipes within our system. This includes recipes, tags and ingredients. We start in this video by using the Django management startapp command to create our app.

Add tag model

We will start by adding a simple tag model to our project. First we will create a test for our model, simply to confirm that it translates a tag to a string representation. Then we will create our model and model migration, as well as enable it in the Django admin. Finally we will run our tests to ensure our model has been created successfully.

Add tests for listing tags

Now we have our model, we can move onto creating our list tags API. We'll start by adding some unit tests and setting up our test structure for our tags. The tests we will write will: ensure that authentication is enabled, check we can retrieve a list of tags, and check that the tags listed are owned by the authenticated user.

Add feature to list tags

Next we will add our list tags feature. This will consist of a ModelSerializer called TagSerializer and a GenericViewSet with the ListModelMixin.

Add create tags feature

Next we will add our create tags feature. We will start by adding a test to ensure that a tag is created successfully when making an HTTP POST request to the tags URL, and confirming that the test fails. Then we will modify our TagViewSet to support creating new models by adding the CreateModelMixin. We will also override the perform_create() function to ensure that tags are assigned to the correct user.

Create ingredients endpoint

Add ingredient model
Add tests for listing ingredients
Implement feature for list ingredients

Now we have our tests we can go ahead and implement our list ingredients feature. For this we need to add a new serializer, view and URL to make our API available.

Implement feature for creating ingredients

Now we have our tests we can go ahead and implement our list ingredients feature. For this we need to add a new serializer, view and URL to make our API available.

Re-factor tags and ingredients viewsets

The great thing about Test Driven Development is that we can re-factor our code with confidence that it won't have an adverse affect on other parts of the project. Since a lot of our ingredients and tags API are similar, we are going re-factor this to improve our source code. We'll do this by creating a new class which contains the common functionality for both tags and ingredients.

Create recipe endpoint

Add recipe model

Now we are going to move onto the main part of our API, the recipe endpoints. We'll start by creating a new model to store our recipes in the database.

Add tests for listing recipes

Next we will create our API for listing recipes. For our tests, we are going to start by creating some helper functions for creating recipes, tags and ingredients. This will make our testing smoother by reducing the duplicate code.

Implement feature for listing recipes

Now that we have our tests we can implement our feature to make them pass. We will start by adding a new serializer to handle recipe objects. Then we'll create a view which we will connect up to our URLs.

Add tests for retrieving recipe detail

Now we can list recipes we can add support for retrieving the details of a recipe. When designing APIs it's often a good idea to limit the data displayed in the list view, but make it accessible using a detail view. This helps to keep the API fast and gives the consumer of the endpoint flexibility to retrieve the data they require at the time. When listing recipes we are only going to show the IDs of the tags and ingredients that are assigned, and in the detail view we will display the rest of the details such as ingredient and tag name.

Implement feature for retrieving recipe detail

Next we can implement our recipe detail endpoint and make our tests pass. We'll do this by creating a serializer for our recipe detail view, and override our get_serializer_class() function to return the detail serializer when retrieving specific items.

Add tests for creating recipes

Next we will add the ability to create recipes.

Implement feature for creating recipes

Now we have our tests created we can implement the feature and make them pass. Because of the greatness of Django REST Framework, this is surprisingly easy to do. The only thing we need to do is override the perform_create() function in our ModelViewSet.

Add tests for updating recipes

Next we are going to add a few more tests for updating recipe model objects.

Add upload image endpoint

Add Pillow requirement

In this section, we are going to add the ability to upload images for our recipes. For this, we need to add a new requirement to our project so we can use Django's ImageField to save our file. We'll also change our Django configuration file to support storing our staticfiles in our docker container.

Modify recipe model

Next we can add our new field to our recipe model. We'll start by adding a test to ensure that the image is saved with the correct filename. We are going to generate a uuid for each image to ensure the filename is unique.

Add tests for uploading image to recipe

Next we are going to add tests for uploading images to our recipe model.

Add feature to upload image

Next we will implement the feature to upload images, to make our tests pass. We'll do this by adding a new action to our Recipe viewset. We'll also create a custom serializer, and modify our get_serializer_class() function to return the correct serializer when using our upload image action.

Add filtering

Add tests for filtering recipes

Next we will modify our API to support filtering recipes using ingredients and tags. We start by adding some unit tests for ensuring the filters are applied correctly.

Implement feature to filter recipes

As per our unit tests, filtering will be done using query parameters passed into the get requests. We'll implement this in this video and ensure the tests pass.

Add tests for filtering tags and ingredients

In this video we will add an option to our tags and ingredients API that allows the user to filter by items assigned to recipes. This allows users to exclude any ingredients that are not being used, which may help the API user when listing tag/ingredient options to filter by.

Implement feature for filtering tags and ingredients

Now we will implement our feature for filtering tags and ingredients, by checking for the assigned_only query parameter.


What was covered in this course
You can view and review the lecture materials indefinitely, like an on-demand channel.
Definitely! If you have an internet connection, courses on Udemy are available on any device at any time. If you don't have an internet connection, some instructors also let their students download course lectures. That's up to the instructor though, so make sure you get on their good side!
4.5 out of 5
511 Ratings

Detailed Rating

Stars 5
Stars 4
Stars 3
Stars 2
Stars 1
30-Day Money-Back Guarantee


8 hours on-demand video
2 articles
Full lifetime access
Access on mobile and TV
Certificate of Completion