Output Archive
Output Archive
UNIVERSITY
FACULTY OF INFORMATICS
Bachelor's Thesis
MICHAL SOLTIS
Bachelor's Thesis
MICHAL ŠOLXIS
Michal Šoltis
iii
Acknowledgements
iv
Abstract
Keywords
v
Contents
Introduction 1
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
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
viii
Introduction
1
1 Python Web Frameworks
2
i . P Y T H O N W E B FRAMEWORKS
^ ^ ^ ^ ^ ^ ^ ^ ^ 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
1.1 Django
3
i . P Y T H O N W E B FRAMEWORKS
1.2 Flask
1.3 FastAPI
4
2 Django Basics
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>
• asgi.py 1
• settings.py
• urls.py
• wsgi.py 2
5
2. D J A N G O BASICS
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:
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
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
7
2. D J A N G O BASICS
2.4 Database
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
2.6 URLs
9
2. DJANGO BASICS
Django administration
Site administration
None available
10
3 Technology Stack
11
3- T E C H N O L O G Y STACK
3.4 Celery
12
3- T E C H N O L O G Y STACK
13
4 Building a REST API
14
4- B U I L D I N G A R E S T API
APPLICATION
(^Create/Delete schedule
o
Create/Update/Delete leagues/teams
/\
Admirf
4.2 Dependencies
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
/parent/{parent_pk}/child/{child_pk}
@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
class LeagueList(APIView):
def get (
s e l f , request : Request
) -> Response :
def post (
s e l f , request : Request
) -> Response :
• Generic ViewSet 1
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
22
4- B U I L D I N G A R E S T A P I
Leagues List
GET /football/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
23
4- B U I L D I N G A R E S T A P I
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],
Jsemame adniir
Email [email protected]
Arsenal
Asian Villa
Brentford
Bi c h I o -
Bur" sy
Chelsea
Crystal Palace
Ev&'tcn
4.8 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
Register
GET /register/
25
5 Testing and Optimization
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/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
27
5. TESTING A N D OPTIMIZATION
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
ittttMJM 200GET /foot ball/pre i ier leag e/fixtures/ 926^: overall 24m o n queries 2 queries
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
luwotas 2 0 0 GET /football/pre i ier leag e/results/ 503ms overall 5 4 . on queries 2 queries
5.2.1 Optimization
28
5. TESTING A N D OPTIMIZATION
29
Conclusion
30
Bibliography
31
BIBLIOGRAPHY
32
A An appendix
Part of the thesis is a zip file, which contains source files of the entire
project.
33