0% found this document useful (0 votes)
58 views42 pages

Output Archive

Uploaded by

Muler Taye
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
58 views42 pages

Output Archive

Uploaded by

Muler Taye
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

MASARYK

UNIVERSITY
FACULTY OF INFORMATICS

Advanced REST API Development


with Django

Bachelor's Thesis

MICHAL SOLTIS

Brno, Spring 2023


MASARYK
UNIVERSITY
FACULTY OF INFORMATICS

Advanced REST API Development


with Django

Bachelor's Thesis

MICHAL ŠOLXIS

Advisor: Mgr. Luděk Bártek, Ph.D.

Department of Computer Systems and Communications

Brno, Spring 2023


Declaration

Hereby I declare that this paper is my original authorial work, which


I have worked out on my own. A l l sources, references, and literature
used or excerpted during elaboration of this work are properly cited
and listed i n complete reference to the due source.

Michal Šoltis

Advisor: Mgr. Luděk Bártek, Ph.D.

iii
Acknowledgements

I want to thank my family and friends for their support during my


academic journey. I am grateful for their contributions and everything
they have done for me. Their love has been a source of strength and
inspiration. Without them, I could not reach this milestone i n my life.
Thank you once again.

iv
Abstract

The aim of the thesis is to explore a high-level Python web framework


Django and provides insight into the framework's capabilities, best
practices, and standard patterns. Part of the thesis is the implementa-
tion of the REST A P I with Django, serving as a demo application. This
demo application helps cover Django's advanced concepts alongside
various valuable tools for REST A P I development i n general.

Keywords

Python, Django, REST A P I , Backend, Web development

v
Contents

Introduction 1

1 Python Web Frameworks 2


1.1 Django 3
1.2 Flask 4
1.3 Fast A P I 4

2 Django Basics 5
2.1 Project structure 5
2.2 Models 7
2.3 ORM 7
2.4 Database 8
2.5 Views 8
2.6 URLs 9
2.7 A d m i n interface 9
2.8 Development server 10
2.9 Commands summary 10

3 Technology Stack 11
3.1 REST A P I 11
3.2 REST A P I criteria 11
3.3 Django REST framework 12
3.4 Celery 12

4 Building a REST API 14


4.1 Use Case Diagram 15
4.2 Dependencies 16
4.3 E R D diagram 16
4.4 Serializers 18
4.5 View sets 20
4.6 Routers 22
4.7 Background tasks 23
4.8 Signals 24

5 Testing and Optimization 26

vi
5.1 Automated Testing
5.1.1 Code quality
5.2 Performance Testing
5.2.1 Optimization

Conclusion

Bibliography

A An appendix
List of Figures

1.1 Python web frameworks popularity [3] 3


2.1 Django administration panel 10
4.1 Use Case Diagram 15
4.2 Entity Relationship Diagram 17
4.3 Django REST framework browsable A P I 23
4.4 REST A P I profile endpoint 24
4.5 REST A P I register endpoint 25
5.1 Locust performance test 27
5.2 Silk profiling dashboard 28

viii
Introduction

The concept of REST or RESTful A P I has become a fundamental build-


ing block for software development. REST (REpresentational State
Transfer) is a set of architectural constraints and provides a standard-
ized set of guidelines for creating web services and efficient commu-
nication between client applications and server backends [1].
Python web framework Django provides a flexible platform for
building web applications. It has gained popularity among developers
due to its versatility and pragmatic design. The Django and REST A P I
combination is a good starting point for backend development.
The primary goal of this thesis is to provide an overview of the
current state of the Django framework and to demonstrate the devel-
opment of REST A P I with Django using a practical and illustrative ex-
ample. The final application is a simple sports platform that simulates
matches i n the leagues by randomly generating data. The frontend
development is not part of this thesis.
Chapter 1 presents an overview and comparison of Python web
frameworks. Chapter 2 contains the general development workflow
with Django and its basic concepts. Chapter 3 summarizes the technol-
ogy I used during development. Chapter 4 demonstrates the design
and implementation process of the REST A P I w i t h the Django REST
framework. Finally, chapter 5 concludes the thesis w i t h a short expla-
nation of the testing and optimization process of the REST APIs.
In conclusion, this thesis contributes to a better understanding of
Python web development using various tools possibly applicable to
any Python project.

1
1 Python Web Frameworks

Python has become popular i n web development, w i t h numerous


frameworks available for creating and managing web applications,
web services, or websites. These frameworks offer various features and
benefits, making Python a popular language for web development.
U s i n g a framework to implement an idea may require following
many conventions, standards, and rules. Some frameworks do not let
developers implement their ideas i n their way, meaning the frame-
works force developers to use "prescribed architecture" in the projects.
The solution might be a reverse strategy, choosing the project's archi-
tecture first and then finding the appropriate framework for it [2].
This chapter summarizes and shows the differences among the
three most popular Python web frameworks based on the JetBrains
Python Developers Survey from 2021 [3]. These are Flask, Django,
and FastAPI.
Each year, the survey reveals the current state of the language.
Python developers submit multi-answer questions regarding various
areas of Python. In 2020, over 23,000 Python developers and enthusi-
asts from almost 200 countries took this survey. Figure 1.1 shows the
results of the question regarding the usage of web frameworks. Flask,
Django, and FastAPI have a big lead over other frameworks.

2
i . P Y T H O N W E B FRAMEWORKS

Frameworks and Libraries

Web frameworks 100*

^ ^ ^ ^ ^ ^ ^ ^ ^ m 41% Flask
^ ^ ^ ^ ^ ^ ^ ^ H 40% Django
^ ^ ^ H 21% Fast A PI
• 4% Tornado
• 3% web2py
_ • 3% Bottle
• Z% CherryPy
• 35b Pyramid
1 2% Falcon
I 1% Hug
5% Other
29% None

Figure 1.1: Python web frameworks popularity [3]

1.1 Django

Django is a free and open-source web framework prioritizing rapid


development and clean, practical design. It provides high productivity
and efficiency for web development. It has many built-in features
that help developers b u i l d and compose robust applications w i t h
other previously written components. The official documentation of
Django itself characterizes the framework as "the web framework for
perfectionists w i t h deadlines" [4].

3
i . P Y T H O N W E B FRAMEWORKS

Many big companies use Django, for example, Youtube, Instagram,


Spotify, or Dropbox.
For more information about Django, visit the official documenta-
tion [4].

1.2 Flask

Flask is considered a micro web framework. In this context, micro


refers to its simplicity. It is easier to learn than Django because Flask
does not mandate specific dependencies or structure of the project.
Instead, it allows developers to select their preferred tools and libraries.
Additionally, many community-supported extensions are available
that simplify incorporating new features into the Flask project.
For more information about Flask, visit the official documenta-
tion [5].

1.3 FastAPI

FastAPI is a relatively new framework released at the end of 2018. It


has a smaller community than Django or Flask.
The framework uses type hints as its foundation. FastAPI requires
explicitly adding a type annotation to the API, unlike previously men-
tioned frameworks. The actual data validation and error handling are
done automatically.
A s the name suggests, the framework provides high performance
and the ability to create APIs fast. It belongs among the top fastest
Python web frameworks.
For more information about FastAPI, visit the official documenta-
tion [6].

4
2 Django Basics

This chapter gives an overview of how to use Django to start develop-


ing web applications.
Django is straightforward regarding conventions, standards, and
the project's architecture. In this thesis, I often refer to these conven-
tions and standards.

2.1 Project structure

The creation of a new Django project can be initiated through the use
of the following command:

django-admin s t a r t p r o j e c t <name>

U p o n execution of this command, an initial directory w i l l be gen-


erated, serving as the fundamental structure of the entire project.
Outside this directory, Django also creates a file named manage. py.
The manage .py file is a wrapper for the dj ango-admin command.
U p o n invoking the manage. py file, the DJANGO_SETTINGS_MODULE en-
vironment variable is automatically set to reference the s e t t i n g s . py
module i n the initial project directory. Thus, the following syntax can
be implied to execute any command related to the Django project:

python manage.py <command>

The initial directory contains these files:

• asgi.py 1

• settings.py

• urls.py

• wsgi.py 2

1. Asynchronous Server Gateway Interface


2. Web Server Gateway Interface

5
2. D J A N G O BASICS

Every Django project is composed of various apps or app com-


ponents. A l l apps must be registered i n the list of INSTALLED_APPS,
as shown below, i n the s e t t i n g s . py module, which already contains
some apps that every Django project includes by default. One of the
benefits of using Django is that developers do not have to start their
projects from scratch, but they can b u i l d the final project on these
pre-installed apps.
Generally, every app component should be reusable and responsi-
ble for one thing. Before implementing a new project, redistributing
functionality into multiple apps is a good practice. Hence, they are
not dependent on each other, making them reusable for other projects.
This process allows the creation of a cohesive and structured Django
project w i t h organized and distinct app components, w i t h one core
app that connects and manages the other app components. The idea
is similar to modular design principles . 3

INSTALLED_APPS = [
"dj a n g o . c o n t r i b . a d m i n " ,
"dj a n g o . c o n t r i b . a u t h " ,
"dj a n g o . c o n t r i b . c o n t e n t t y p e s " ,
"dj a n g o . c o n t r i b . s e s s i o n s " ,
"dj ango.contrib.messages",
"dj a n g o . c o n t r i b . s t a t i c f i l e s " ,
]
The following command generates a new directory i n the root
folder of the project, which represents the new app:

python manage.py startapp <name>

The directory contains various files crucial for the app functionality,
including a migrations directory.
The module apps . py contains a simple configuration of the app.
Other filenames w i t h i n the directory are self-descriptive, providing
insight into their purpose within the app's architecture.

• migrations

3. For more information about m o d u l a r design, visit - h t t p s : / / e n . w i k i p e d i a .


org/wiki/Modular_design

6
2. D J A N G O BASICS

• admin.py

• apps.py

• models.py

• tests.py

• urls.py

• views.py

2.2 Models

Usually, the first step in every Django project is to figure out and design
data models. A l l models of an app should be defined in the models. py
module. Each model represents a single table i n the database. The
names of the tables start with the prefix of the corresponding name of
the app.
The i d attribute is added to all models by default but can be re-
placed w i t h any attribute as a unique key.

2.3 ORM

Object-relational mapper (ORM) is a technique to map data between


a relational database and an object-oriented programming language.
In other words, it is an abstraction above the database.
Django has its own O R M , which allows performing C R U D (Create,
Read, Update, Delete) operations on models, which are reflected in the
database. However, Django also provides the flexibility to execute raw
SQL queries when necessary, which allows developers to have greater
control over the queries executed on the database. They are helpful
when working w i t h complex data models or queries that cannot be
expressed using O R M .
In Django, all queries or query sets are lazy, w h i c h means that
a query set is not evaluated and does not hit the database until the
requested data are needed. After the first evaluation of the query set,
Django stores the result i n the so-called query cache. However, the
entire query must be evaluated.

7
2. D J A N G O BASICS

2.4 Database

Database settings are located in the s e t t i n g s . py module. Initially, the


default SQL database engine for Django is the library SQLite.
SQLite is simple and fast and wraps the database into a single file.
DATABASES = {
"default": {
"ENGINE": " d j a n g o . d b . b a c k e n d s . s q l i t e 3 " ,
"NAME": BASE_DIR / " d b . s q l i t e 3 " ,
}
}

Every app contains a migrations folder.


Migrations are used to create or update tables i n the database. A
migration file is a Python module located i n the migrations folder
of a corresponding app. It contains instructions to create tables and
fields i n the database. The file's name is made from the sequence
number and auto-generated name, w h i c h can be manually changed
for a more descriptive name. Django offers other commands to work
with migrations, such as reverting and squashing. It is very similar to
working w i t h a versioning system. Each migration is like a commit.
The first command below creates initial migrations. These migra-
tions are pushed to the database v i a the second command below.
The command runs through all installed apps and pushes the latest
changes to the database by executing instructions in the migration files.
The first execution also pushes the latest changes from all pre-installed
apps that the Django project contains by default.

python manage.py makemigrations


python manage.py migrate

2.5 Views

Django views are Python functions that take H T T P requests and return
H T T P responses. These functions are so-called request handlers. By
convention, each app's views are defined in the views . py module. The
filename might be confusing since the w o r d view can be associated

8
2. D J A N G O BASICS

w i t h something a user can see. In Django, for some reason, request


handlers are called views.

2.6 URLs

Views or view functions are mapped to U R L s . The U R L s of each app


should be defined i n the u r l s .py module. Every app can have its
own U R L configuration. The initial project directory contains another
u r l s . py module, the central U R L configuration.
To map U R L s to views i n each app's corresponding u r l s . py mod-
ule, Django looks for a special variable called u r l p a t t e r n s . It is an
array of U R L pattern objects that map views to U R L s . Also, this vari-
able is located i n the main u r l s . py module i n the project directory
and contains the U R L configuration of all app components.

2.7 Admin interface

One of the notable features of Django is its admin interface, w h i c h


developers can use as an internal management tool. It is an app that
the initial project template contains by default. This interface enables
admin users to manage the sources across the whole Django project.
In each app, the admin. py module holds customization of the ad-
m i n panel of that app and the registration of models to make them
manageable i n the admin interface. A Figure 2.1 shows the front page
of the admin site.
The following command creates a super user (admin user) w i t h
access to the admin interface.

python manage.py createsuperuser

9
2. DJANGO BASICS

Django administration

Site administration

AUTHENTICATION AND AUTHORIZATION


Recent actions

Groups + Add >/ Charge

Users + Add # Charge My actions

None available

Figure 2.1: Django administration panel

2.8 Development server

The Django development server is a lightweight web server included


in the Django web framework.
The server offers a valuable feature of automatically reloading
the Python code for each incoming request, which allows to preview
the changes i n the applications i n real time. However, some opera-
tions, such as adding files, may not trigger the automatically reload
mechanism. In such cases, a manual server restart is necessary.
The following command initiates the development server. The
development server initializes o n the localhost IP address, w i t h port
8000 being the default configuration. The web page shows a rocket
with the congratulations label, indicating the successful server launch.

python manage.py runserver

2.9 Commands summary

django-admin startproject <name>


python manage.py startapp <name>
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver

10
3 Technology Stack

This chapter provides an overview of the key technologies utilized i n


the demo project, including their theoretical basis.

3.1 REST API

REST (REpresentational State Transfer) is an architectural style for


building web services. Unlike a protocol or standard, REST defines a
set of constraints that A P I developers can follow to create scalable and
flexible web services. When a client sends a request to a RESTful API, it
receives a representation of the resource state i n a format such as JSON,
H T M L , or plain text. J S O N is the most commonly used among these
formats, as it is language-agnostic, human-readable, and machine-
understandable. By adhering to REST's principles, A P I developers
can build web services that are easy to maintain, evolve, and integrate
with other systems [1].

3.2 REST API criteria

For an A P I to be considered RESTful, it must meet the following


criteria:

1. A client-server architecture w i t h H T T P managing requests and


resources are defined as separate entities.

2. A client-server architecture w i t h H T T P managing requests and


resources are defined as separate entities.

3. Stateless communication between client and server means each


request must be self-contained and not depend on previous ones,
and the server cannot store any client data.

4. The ability to cache data enhances client-server interactions and


reduces network traffic.

5. A uniform interface between components, allowing information


to be transmitted i n a standardized format, which requires:

11
3- T E C H N O L O G Y STACK

(a) Resources must have a unique identifier and be separate


from the representation sent to the client.
(b) The representation sent to the client should contain all the
necessary information to allow it to modify the resources.
(c) Self-descriptive messages returned to the client should i n -
clude enough information to specify how the client should
handle them.
(d) Hypertext/hypermedia links should be available to help
the client navigate to other available actions.

6. A layered system that organizes the server functions into hier-


archies that are invisible to the client, such as security or load-
balancing.

7. Code-on-demand is optional, which means the server can trans-


mit executable code to the client upon request, allowing for more
extensive client capabilities.

Meeting these criteria ensures that the A P I conforms to the RESTful


architectural style and follows a standardized approach for building
web services that are scalable, flexible, and easy to maintain [1].

3.3 Django REST framework

To create REST A P I w i t h Django, I installed the Django REST frame-


work package, available from [7]. The framework comes w i t h much
built-in functionality, including authentication, serialization, and brows-
able A P I , w h i c h generates human-friendly output for each resource
of A P I . It improves the usability of REST A P I for developers w i t h
customizable frontend and browsing. The browsable A P I allows the
creation of resources by submitting an H T M L form instead of J S O N
format.

3.4 Celery

Executing tasks, such as video processing, report generation, or send-


ing emails, w i t h i n the primary application process can result i n the

12
3- T E C H N O L O G Y STACK

application becoming unresponsive to client requests. In order to pre-


vent this behavior and maintain accessibility and responsiveness to
client requests, these tasks should be executed i n the background.
This approach enables the application to execute numerous tasks si-
multaneously without impacting the performance of the main app
process.
Flower and Celery are Python libraries commonly used in Django
projects for background task processing.
Celery is a distributed task queue that enables asynchronous task
execution across multiple workers. Task queues are used to distribute
work across threads or machines. Celery communicates via messages,
usually using a broker to mediate between clients and workers [8]. In
this context, a client can be any process or system, such as a Django
web application.
Celery documentation recommends multiple broker transport al-
ternatives, for example, RabbitMQ, Redis, Amazon S Q S , or Zookeeper.
I used Redis because it is easy to set up i n Django. Also, Redis is an
in-memory key/value data store and can be used as a database, cache,
or message broker [ 9 ] .
To initiate a task, the client adds a message to the queue, and the
broker then delivers that message to a worker.
Flower is a web-based monitoring and administration tool for Cel-
ery. It provides a user-friendly dashboard for viewing the status of task
queues, inspecting individual tasks, and monitoring Celery workers
in real time.

13
4 Building a REST API

The final result of the application is a functional system that simulates


matches and events in football leagues by generating randomized data.
The results of matches are randomly generated, favoring the home
team, which has a slightly higher probability of scoring more goals in
that particular match than the away team. The system generates more
random data but accurately and precisely to a football match - team
statistics, player statistics, match summary and commentary.
The implementation covers only the backend site, meaning it does
not support any frontend-services. Although, it uses built-in static
files provided by the Django REST framework and its browsable A P I .
The primary focus is developing a robust REST A P I w i t h a relational
database.
A website user can create an account, log i n and choose their fa-
vorite leagues and teams. After the creation of the account, a user
receives a confirmation email, as confirmation, that their account was
successfully created.
Also, users receive notifications i n the form of an email about the
latest results of their favorite teams. The email contains a short message
w i t h the result of that match. Once per week, users receive another
informative email, which is an update of standings in all their favorite
leagues.
The use case diagram 4.1 summarizes the system's behavior.

14
4- B U I L D I N G A R E S T API

4.1 Use Case Diagram

APPLICATION

(^Create/Delete schedule

o
Create/Update/Delete leagues/teams
/\
Admirf

Figure 4.1: Use Case Diagram


15
4- B U I L D I N G A REST A P I

4.2 Dependencies

To avoid security and compatibility issues, creating a virtual envi-


ronment for a Python project is a best practice to keep third-party
libraries away from the operating system. There are many tools how
for handling virtual environments. Part of the Python standard library
is venv, which adds no extra functionality except for creating a virtual
environment.
I keep all installed dependencies by myself and their extra depen-
dencies separately because it usually results i n a complex recursive
tree of all project dependencies. Therefore, I created one file for keep-
ing dependencies that I installed i n one file (requirements . i n ) , and
then all transitive dependencies, including their versions, contain a
standard requirements . t x t file.

4.3 ERD diagram

Based on my models, I generated an E R D diagram using a Django


app called dj ango-extensions, which allows to create a class diagram
from models of specified apps and return it as an image. The diagram
holds relations among all classes as well as their alphabetically sorted
fields. The output is shown i n Figure 4.2.
Generally, the U R L address does not contain an i d of the objects
as a U R L slug to make it easier for search engines to find content. I
included a slug field into many classes, which is auto-generated from
other attributes before saving the object i n the database.

16
4- B U I L D I N G A R E S T A P I
4- B U I L D I N G A R E S T A P I

4.4 Serializers

Serializer converts data models and complex queries from the database
into types understandable by frontend frameworks, such as J S O N
or X M L . It is conventional i n Django to place serializer classes i n a
separate Python module called s e r i a l i z e r s .py.
I used the M o d e l S e r i a l i z e r and H y p e r l i n k e d M o d e l S e r i a l i z e r
classes available i n the Django REST framework [7].
H y p e r l i n k e d M o d e l S e r i a l i z e r is the same class as M o d e l S e r i a l i z e r ,
except it includes the u r l field of the object, w h i c h is handy w h e n
browsing i n the REST A P I .
These classes are closely related to the model definitions and pro-
vide a simplified way to define serializers and avoid the redundancy
of defining all attributes of a model. They include predefined valida-
tion, representation, and other methods to avoid duplication across
all serializer classes. These methods can be overwritten to custom
implementation.
Changing the default value of the lookup_f i e l d keyword in these
classes is necessary to reflect the slug field i n the U R L s .
c l a s s League (models . Model) :
name = models.CharField(max_length=50)
slug = m o d e l s . S l u g F i e l d ( u n i q u e = T r u e )
country = C o u n t r y F i e l d ( )
season = m o d e l s . P o s i t i v e S m a l l l n t e g e r F i e l d ()

class LeagueSerializer(
NestedHyperlinkedModelSerializer
):
c l a s s Meta:
model = League
fields = [
"url" ,
"name" ,
"country" ,
"season" ,
"results" ,
"fixtures" ,

18
4- B U I L D I N G A R E S T A P I

"standings",
]
extra_kwargs = {
"url": {
"lookup_field": "slug"
}
}

country = C o u n t r y F i e l d (
name_only=True
)
results = NestedHyperlinkedldentityField(
read_only=True,
view_name = " r e s u l t s - l i s t " ,
lookup_url_kwarg="league_slug",
parent_lookup_kwargs={
"league_slug": "slug"
},
)
fixtures = NestedHyperlinkedldentityField(
read_only=True,
view_name="fixtures-list",
lookup_url_kwarg="league_slug",
parent_lookup_kwargs={
"league_slug": "slug"
},
)
standings = N e s t e d H y p e r l i n k e d l d e n t i t y F i e l d (
read_only=True,
view_name = " s t a n d i n g s - l i s t " ,
lookup_url_kwarg="league_slug",
parent_lookup_kwargs={
"league_slug": "slug"
},
)
In the example above, LeagueSerializer is a subclass
of NestedHyperlinkedModelSerializer, which extends the function-

19
4- B U I L D I N G A R E S T A P I

ality of H y p e r l i n k e d M o d e l S e r i a l i z e r and allows the addition of hy-


perlinks of nested resources.
Nested resources are used when one resource is contained/nested
within another resource. The U R L structure can represent this rela-
tionship by including the parent and child resources i n the U R L path.
The desired U R L signature looks like this:

/parent/{parent_pk}/child/{child_pk}

U s i n g nested resources i n REST APIs can help to organize re-


sources and provide a clear U R L structure that reflects the relation-
ships between resources. Nested serializer classes are part of the
d r f - n e s t e d - r o u t e r s package [10]. Nested routers are explained i n
the section below 4.6.

4.5 View sets

To make a view function appear i n browsable A P I from the Django


REST framework, it needs to have @api_veiw() decorator, which takes
a list of allowed H T T P methods as an argument.
from rest_framework.request import Request
from rest_framework.response import Response

@api_view(["GET", "POST"])
def l e a g u e _ l i s t ( r e q u e s t : Request) -> Response:
i f request.method == "GET":
queryset = ...
s e r i a l i z e r = ...
return Response(serializer.data)
e l i f request.method == "POST":
queryset = ...
s e r i a l i z e r = ...
return Response(serializer.data)
Django REST framework supports function-based views as well as
class-based views. Often, H T T P methods, represented by these views
functions, use similar logic w h e n dealing w i t h different resources or
models. Each method has a similar query and then returns data from

20
4- B U I L D I N G A R E S T A P I

this query passed to a serializer class. To avoid duplication across


these functions, I used class-based views, w h i c h combine the same
logic of multiple related views i n one class. The example below is a
class-based view, which inherits from APIView parent class. It reduces
some duplication by hiding multiple if statements.
from rest_framework.views import APIView

class LeagueList(APIView):
def get (
s e l f , request : Request
) -> Response :

def post (
s e l f , request : Request
) -> Response :

To simplify class-based views even more, Django supports so-


called view sets. A view set class inherits from mixin classes, w h i c h
provide action methods similar to H T T P methods.
• CreateModelMixin - create model instance

• RetrieveModelMixin - retrieve model instance

• UpdateModelMixin - update model instance

• DestroyModelMixin - destroy model instance

• ListModelMixin - list model instances

• Generic ViewSet 1

These five mixins and the GenerViewSet class compose together


compose ModelViewSet, w h i c h supports executing all H T T P meth-
ods. A n y combination of these mixins is applicable. For example,
RetrieveModelMixin and ListModelMixin compose ReadOnlyViewSet.

1. The Generic ViewSet class does not provide any actions by default but does
include the base set of generic v i e w behavior, such as the g e t _ o b j e c t a n d
get_queryset methods.

21
4- B U I L D I N G A R E S T A P I

The view set class must contain at least two attributes: queryset for
querying the objects from the database and s e r i a l i z e r _ c l a s s for seri-
alizing these objects. M e t h o d s ( g e t _ q u e r y _ s e t , g e t _ s e r i a l i z e r _ c l a s s )
can overwrite these attributes if, for example, the queryset attribute
requires specific logic for different H T T P methods handlers.
c l a s s LeaguesViewSet(ReadOnlyModelViewSet):
lookup_field = "slug"
queryset = L e a g u e . o b j e c t s . a l l ( )
s e r i a l i z e r _ c l a s s = LeagueSerializer
These view sets make a significant level of abstraction compared
to view functions, but they confirm one of Django's principles, which
encourages rapid development and clean, pragmatic design.

4.6 Routers

Automated registration of views to U R L patterns can be achieved


through a router. The process of registering view sets with the router
is highly abstract and simplifies the overall implementation of the API.
The U R L configuration of the app contains the U R L patterns of router
URLs.
However, when using nested resources, a nested router is required.
Since the Django REST framework does not provide a nested router,
I had to use the same package I used to add hyperlinks of nested
resources [10].
The appearance of the browsable REST A P I is illustrated i n the
Figure 4.3.

22
4- B U I L D I N G A R E S T A P I

Django REST framework

Api Root Leagues List

Leagues List
GET /football/

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

'country": "United Kingdom",


•season": 2023,
•resJits": "http://127.0.0.1:8000/football/premier-league/resjits/",
•fixtures": "http:1/127.0.0.1:8000/football/premier-league/fixtures/",
•standings": "http://127.0.0.1:8000/football/premier-league/standings/"

Figure 4.3: Django R E S T framework browsable A P I

4.7 Background tasks

Whenever an a d m i n user generates matches via the admin interface,


the system schedules asynchronous tasks at a fixed time. It generates
data for each match as a background task 90 minutes after the fixed
match start and then sends an email, w i t h the result, to all users that
mark one of the teams as their favorite. The match is marked as active
in the REST A P I during these 90 minutes.
The system has one more scheduled periodic task for notifying
users about the latest standings i n their favorite leagues. Figure 4.4
shows the profile endpoint, which allows marking the user's favorite
teams and leagues.

23
4- B U I L D I N G A R E S T A P I

Django REST framework

Api Root Profile

Profile

HTTP 2BS OK
allow: SET, PUT, DELETE
ton tent-Type: appLicatior,-'jscn
Vary: Accept

i
"user-name": "admin",
"email": "admiri^test.c;Vj
*«y_le*Cues": I],

Raw data HTML form

Jsemame adniir

Required. 150 characters or feiver L&tters, digits and @/J+l-I_ only.

Email [email protected]

My laagues Premier League

Arsenal
Asian Villa
Brentford
Bi c h I o -
Bur" sy
Chelsea
Crystal Palace
Ev&'tcn

Figure 4.4: R E S T A P I profile endpoint

4.8 Signals

Django offers a set of pre-built signals that enable user-defined code


to receive notifications for specific events within the framework. These
signals are implemented at the model level and are triggered during
various stages of the model's lifecycle. Examples of commonly used
signals:

• pre-save

• post-save

• pre-delete

24
4- B U I L D I N G A R E S T A P I

• post-delete

Functions or apps can listen to these signals and perform other


actions after they receive a signal. The responsibilities are better dis-
tributed across multiple blocks of code. The functions that listen to
particular signals are called signal handlers.
Modules that define signals and signal handlers must be imported
by overriding the ready () method i n the app. py module i n the con-
figuration class of the app.
I implemented a signal handler, which listens to a post_save signal
of the User model. A newly created User object fires a p o s t s a v e
signal whenever a website user creates an account. The following code
snippet is a signal handler that listens to the p o s t s a v e signal from
the User model and sends a confirmation email to a new user that
their account was successfully created.
Figure 4.5 shows the registration endpoint i n the REST A P I .

Django REST framework

Apl Root Register

Register
GET /register/

HTTP 405 Method Not Allowed


Allow: POST
Content -Type: application/;: = on
Vary: Accept

"detail": "Method VGETV not allowed.

Raw data HTML form

Required. 150 characters or fewer. Letters.;! g Is and @fJ+I-f_ only.

Figure 4.5: REST A P I register endpoint

25
5 Testing and Optimization

This chapter explains and demonstrates the REST A P I testing process


on multiple levels.

5.1 Automated Testing

Automated testing can be applied to different types of testing, includ-


ing unit, integration, system, or regression testing.
Python offers, unsurprisingly, multiple test frameworks. I used
the pytest test framework for unit and integration testing because
it allows writing tests w i t h a few lines of code and has a p l u g i n for
testing Django applications.
When writing unit tests, I tried to follow the so-called A A A pattern,
a standard to divide a test among three sections - Arrange, Act, and
Assert.
In designing the tests, I focused on testing the system's behavior,
specifically how A P I endpoints behave, rather than test individual A P I
components, like models, serializers, or views. This approach ensures
flexibility of the tests, even if the implementation of these components
changes i n the future.

5.1.1 Code quality

Usually, part of the testing process in Python projects is ensuring that


the code conforms to specific coding guidelines. Running a separate
command for each static code analyzer is a time-consuming process.
In that situation, a command line tool, tox, could be a helpful solution.
tox is used for managing, creating, and running test environments
in Python projects. A l l test environments are invoked within a single
command and executed inside an isolated environment.

5.2 Performance Testing

Performance testing is another crucial part of testing software quality.


In the context of REST A P I , performance testing is usually done by
sending H T T P requests to various endpoints and determining which

26
5. TESTING A N D OPTIMIZATION

are slower and take too much time to retrieve data from the database
and the limit i n terms of A P I users.
A special type of performance testing is so-called stress testing.
Stress testing is similar to basic performance testing, except the number
of users and their requests is m u c h higher to identify the limits of
A P I users and w h e n the system starts to fail. Stress testing should be
done against the production server because the development server is
usually very slow.
For a demo performance test, I used a performance testing tool
for Python called Locust. It is unrelated to any specific framework.
Figure 5.1 shows the performance test.

QLOCUST
Statistics Charts Failures Exceptions Current ratio D o w n l o a d Data

type Name # Requests 0 Fails M e d i a n (ms) 90% lie (ms) 99%ile (ms) A v e r a g e (ms) Min (ms) Max (ms)

GET /football 61 0 7500 29000 34000 13290 150 33709

GET /football/pre n lier-league 46 0 3900 2&000 32000 10579 131 31896

GET /football/pre n lier-league/fixtures 69 0 5200 13000 15000 6408 194 14857

GET /football/pre n lier- league/results 63 0 7800 13000 16000 6745 179 16114

GET /football/pre n lier- league/standings 66 0 5200 13000 16000 6213 178 15732

Aggregated 305 0 5200 23000 32000 8441 131 33709

Figure 5.1: Locust performance test

A n a l y z i n g project performance is called profiling. For profiling


A P I endpoints, I used Silk, a live profiling and inspection tool primarily
used for the Django framework. Silk intercepts each request i n the
A P I and collects data displayed on the Silk dashboard at the localhost
web address [11]. Figure 5.2 shows the Silk dashboard and collected
information while processing requests from Locust. The response
times are prolonged because of the overflow added to processing
requests by Silk.

27
5. TESTING A N D OPTIMIZATION

Requests order B ESS5EFB

11:^6:06392 2 0 0 GET /football/pren ier , e a s e/resu Its/ 532ms overall 28m o r q u e r i e s 2 queries

1U6.06 507 2 0 0 GET /football/pren i « e/fixtures/ 541 m o v e i a l l 25m on •,UL ML S , ,


2 queries

iw*06.lfl 2 0 0 GET /tootball/ lOiiWms overall 31 rr on q u e r i e s que'ies

ittttMJM 200GET /foot ball/pre i ier leag e/fixtures/ 926^: overall 24m o n queries 2 queries

11-^6-062:8 2 0 0 GET /football/pren ier •leagi e/ 10631ns overall 3 4 . on queries que'ies

11.^6.05 sw 2 0 0 GET /football/pren ier C/rOSUltS/ 693™ overall 32m on ujuoiil'S

ntttttbtu 2 0 0 GET /football/pre n ier Itcg e/standings/ ^Otjms overall 42m on queries 2 queries

M--6-05 3:-, 2 0 0 GET /foot ball/pre i ier leag e/results/ S45m: overall 42m on queries 2 queries

11:^6:05 353 2 0 0 GET /football/pren ier leag e/fixtures/ 647im overall 50„ on q u e r ' e s 2 queries

n4&mm* 2 0 0 GET /football/ 1?053™ ovimhII 43„ •,, querirs

nttcotjus 2 0 0 GET /football/pre n i « Itcg e/results/ bWAms overall 3y m on q u e r i e s 2 queries

luwotas 2 0 0 GET /football/pre i ier leag e/results/ 503ms overall 5 4 . on queries 2 queries

Figure 5.2: Silk profiling dashboard

5.2.1 Optimization

Optimizing database queries is a commonly recommended technique


for improving performance. Various optimizations can be applied to
the queries to achieve faster response times, such as rewriting queries
with SQL, redesigning the database, or caching.
One of the common factors that can cause an A P I endpoint to slow
d o w n is inefficient querying or accessing the database. The Django
Debug Toolbar is a tool that provides developers w i t h detailed infor-
mation on the performance and behavior of the Django applications.
It is a tool that primarily monitors the database. In a browser, a sidebar
panel shows actions needed to display the current page, including
executed SQL queries. It helps to determine which queries should be
optimized or rewritten.
Django documentation also has database access optimization docu-
ment , which is a summary of all possible query set methods to fasten
1

the database queries.


Another option for improving the performance of the A P I is to
cache data coming from the database. Django has a built-in caching
framework as well. The cache framework supports several caching

1. Database access optimization - https://docs.djangoproject.eom/en/4.l/


topics/db/optimization/

28
5. TESTING A N D OPTIMIZATION

backends, including in-memory caching, file-based caching, database


caching, and caching with external services like Memcached or Redis.
Since I used Redis as a message broker to communicate w i t h Celery
workers, I also used Redis as a cache backend.

29
Conclusion

The thesis comprehensively explores integrating the Django web frame-


work with RESTful A P I development. It includes a practical demonstra-
tion of developing REST APIs using Django and serves as a resource
for readers seeking to leverage Django for their backend development
requirements. The Swagger/OpenAPI 2.0 specification is part of the
A P I at the /swagger endpoint.
The application can be r u n as a Docker container. One of the ap-
plication's source files is a script w a i t - f o r - i t . sh, which waits on the
availability of a host and T C P port. It is useful for synchronizing the
spin-up of interdependent services, such as linked docker containers [12].
A topic for future work might be adding frontend services or ex-
tending the A P I w i t h additional data.

30
Bibliography

1. R E D H A T . What is a REST API? [online]. 2020. [visited on 2023-


05-01]. Available from: https : //www. redhat. com/en/topics/
api/what-is-a-rest-api.
2. A R J A N C O D E S . Clean Architecture vs Django's Pragmatic Design
[online]. 2023. [visited on 2023-05-01]. Available from: https :
//www.youtube.com/shorts/nHd7aYUQMdY.
3. JETBRAINS. Python Developers Survey 2021 Results [online]. 2021.
[visited on 2023-05-01]. Available from: https : / / l p . j e t b r a i n s .
com/python-developers-survey-2021.
4. Django documentation [online]. 2023. [visited on 2023-05-01].
Available from: h t t p s : //docs .djangoproject. com/en/4.2.
5. Flask documentation [online]. 2023. [visited on 2023-05-01]. Avail-
able from: h t t p s : //flask, p a l l e t s p r o j e c t s . com/en/2.2. x.
6. R A M I R E Z , Sebastian. FastAPI documentation [online]. 2023. [vis-
ited on 2023-05-01]. Available from: https : / / g i t h u b . com/
tiangolo/fastapi.
7. Django REST framework [online]. 2023. [visited on 2023-05-01 ].
Available from: h t t p s : //www. d j a n g o - r e s t - f ramework. org.
8. Celery: Distributed Task Queue [online]. 2023. [visited on 2023-
05-01]. Available from: https : //github. com/celery/celery#
whats-a-task-queue.
9. Backends and Brokers - Celery documentation [online]. 2023. [visited
on 2023-05-01]. Available from: https : //docs . c e l e r y q . dev/
en/stable/getting-started/backends-and-brokers/index.
html.
10. SILVA, A l a n Justino da. DRF Nested Routers [online]. 2023. [vis-
ited on 2023-05-01]. Available from: https : / /github . com/
alanjds/drf-nested-routers.
11. G U L E A , Iulian. Guide to Django Performance Testing and Optimiza-
tion [online]. 2023. [visited on 2023-05-01 ]. Available from: h t t p s :
/ / www . t o p t a l . com / python / performance - o p t i m i z a t i o n -
testing-django.

31
BIBLIOGRAPHY

12. H A L L , Giles. Wait for it [online]. 2023. [visited on 2023-05-01 ].


Available from: h t t p s : //github. com/vishnubob/wait-f o r - i t .

32
A An appendix

Part of the thesis is a zip file, which contains source files of the entire
project.

33

You might also like