Last active
November 28, 2022 13:06
-
-
Save ckkz-it/941c4c7b3f03213e8c05cdaa87234e97 to your computer and use it in GitHub Desktop.
Django Rest Framework serializer benchmark for queries count and time estimation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UserSerializer(serializers.ModelSerializer): | |
clients = serializers.ListField(source='client_names') # Model's property to retrieve `clients` names | |
sales = serializers.IntegerField(source='get_sales_overall_amount') # Model's method | |
address = serializers.CharField(source='address.street') | |
manager_name = serializers.CharField(source='manager.full_name') | |
@staticmethod | |
def setup_eager_loading(queryset): | |
""" Perform necessary eager loading of data. """ | |
# select_related for "one-to-many" and "one-to-one" relationships (`ForeignKey`, `OneToOne`) | |
queryset = queryset.select_related( | |
'company', | |
'address', | |
'manager', | |
) | |
# prefetch_related for "many-to-many" relationships (`ManyToMany`) | |
queryset = queryset.prefetch_related( | |
'clients', | |
'sales', | |
) | |
return queryset | |
class Meta: | |
model = User | |
fields = ('id', 'first_name', 'last_name', 'email', 'phone', 'company', 'address', 'manager', 'clients', 'sales') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import django | |
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.name.settings") | |
django.setup() | |
from app.auth.models import User | |
from app.auth.serializers import UserSerializer | |
from app.utils.test_utils import benchmark_serialization | |
def user_serializer_bench(limit=1, should_print_data=False): | |
benchmark_serialization( | |
model=User, | |
serializer_class=UserSerializer, | |
limit=limit, | |
should_print_data=should_print_data, | |
) | |
if __name__ == '__main__': | |
user_serializer_bench(limit=10) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from contextlib import contextmanager | |
from pprint import pprint | |
from time import time | |
from django.db import reset_queries, connection | |
class colors(object): | |
end = '\033[0m' | |
black = '\033[1;30m' | |
red = '\033[1;31m' | |
green = '\033[1;32m' | |
def print_colored(data, color=colors.red, centered=False, print_empty_line=False): | |
if centered: | |
data = ' {} '.format(data).center(40, '-') | |
print('{color}{data}{end}{empty_line}'.format( | |
color=color, | |
data=data, | |
end=colors.end, | |
empty_line='\n' if print_empty_line else '', | |
)) | |
def sql_bench(should_print_sql): | |
indentation = 2 | |
width = 80 | |
total_time = 0.0 | |
if len(connection.queries) > 0: | |
print_colored('queries: {}'.format(len(connection.queries))) | |
for query in connection.queries: | |
total_time = total_time + float(query['time']) | |
if should_print_sql: | |
nice_sql = query['sql'].replace('"', '').replace(',', ', ') | |
sql = '{color}[{time}]{end} {sql}'.format( | |
color=colors.red, | |
time=query['time'], | |
end=colors.end, | |
sql=nice_sql, | |
) | |
while len(sql) > width - indentation: | |
print_colored("{ident}{sql}".format( | |
ident=" " * indentation, | |
sql=sql[:width - indentation] | |
)) | |
sql = sql[width - indentation:] | |
print_colored(sql) | |
print_colored('time spent on queries: {time} seconds'.format(time=str(total_time))) | |
@contextmanager | |
def time_and_queries(name='Unnamed Timing'): | |
reset_queries() | |
print_colored(name, colors.green, centered=True) | |
start_time = time() | |
try: | |
yield | |
finally: | |
overall_time = time() - start_time | |
sql_bench(should_print_sql=False) | |
print_colored('time spent overall: {:.3f} seconds'.format(overall_time)) | |
print_colored('END', centered=True, print_empty_line=True) | |
def benchmark_serialization(model, serializer_class, limit, should_print_data, with_eager_loading=False): | |
print_colored('Benchmark `{serializer_name}` with {limit} item{s}'.format( | |
serializer_name=serializer_class.__name__, | |
limit=limit, | |
s='s' if limit > 1 else '', | |
), colors.black, print_empty_line=True) | |
with time_and_queries('Without Eager Loading'): | |
qs = model.objects.all()[:limit] | |
serializer = serializer_class(qs, many=True) | |
data = serializer.data | |
if should_print_data: | |
pprint(data) | |
if with_eager_loading: | |
with time_and_queries('With Eager Loading'): | |
qs = model.objects.all()[:limit] | |
qs = serializer_class.setup_eager_loading(qs) | |
serializer = serializer_class(qs, many=True) | |
data = serializer.data | |
if should_print_data: | |
pprint(data) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output example:
![preview](https://user-images.githubusercontent.com/39866850/78425156-5ef1d100-7662-11ea-9b8d-82399f545c38.png)