mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-06 21:40:13 +03:00
Added a basic benchmark suite for serializers.
This commit is contained in:
parent
6e2ea852d0
commit
59659835e8
|
@ -5,6 +5,7 @@ Django>=1.4.11
|
||||||
pytest-django==2.8.0
|
pytest-django==2.8.0
|
||||||
pytest==2.6.4
|
pytest==2.6.4
|
||||||
pytest-cov==1.6
|
pytest-cov==1.6
|
||||||
|
pytest-bench==0.3.0
|
||||||
flake8==2.2.2
|
flake8==2.2.2
|
||||||
|
|
||||||
# Optional packages
|
# Optional packages
|
||||||
|
|
|
@ -8,8 +8,8 @@ import subprocess
|
||||||
|
|
||||||
|
|
||||||
PYTEST_ARGS = {
|
PYTEST_ARGS = {
|
||||||
'default': ['tests', '--tb=short'],
|
'default': ['tests', '--tb=short', '--bench'],
|
||||||
'fast': ['tests', '--tb=short', '-q'],
|
'fast': ['tests', '--tb=short', '-q', '--bench'],
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501']
|
FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501']
|
||||||
|
|
10
tests/fields.py
Normal file
10
tests/fields.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class CustomField(models.Field):
|
||||||
|
"""
|
||||||
|
A custom model field simply for testing purposes.
|
||||||
|
"""
|
||||||
|
pass
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from .fields import CustomField
|
||||||
|
|
||||||
|
|
||||||
class RESTFrameworkModel(models.Model):
|
class RESTFrameworkModel(models.Model):
|
||||||
|
@ -68,3 +69,62 @@ class NullableOneToOneSource(RESTFrameworkModel):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
target = models.OneToOneField(OneToOneTarget, null=True, blank=True,
|
target = models.OneToOneField(OneToOneTarget, null=True, blank=True,
|
||||||
related_name='nullable_source')
|
related_name='nullable_source')
|
||||||
|
|
||||||
|
|
||||||
|
class RegularFieldsModel(models.Model):
|
||||||
|
"""
|
||||||
|
A model class for testing regular flat fields.
|
||||||
|
"""
|
||||||
|
auto_field = models.AutoField(primary_key=True)
|
||||||
|
big_integer_field = models.BigIntegerField()
|
||||||
|
boolean_field = models.BooleanField(default=False)
|
||||||
|
char_field = models.CharField(max_length=100)
|
||||||
|
comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=100)
|
||||||
|
date_field = models.DateField()
|
||||||
|
datetime_field = models.DateTimeField()
|
||||||
|
decimal_field = models.DecimalField(max_digits=3, decimal_places=1)
|
||||||
|
email_field = models.EmailField(max_length=100)
|
||||||
|
float_field = models.FloatField()
|
||||||
|
integer_field = models.IntegerField()
|
||||||
|
null_boolean_field = models.NullBooleanField()
|
||||||
|
positive_integer_field = models.PositiveIntegerField()
|
||||||
|
positive_small_integer_field = models.PositiveSmallIntegerField()
|
||||||
|
slug_field = models.SlugField(max_length=100)
|
||||||
|
small_integer_field = models.SmallIntegerField()
|
||||||
|
text_field = models.TextField()
|
||||||
|
time_field = models.TimeField()
|
||||||
|
url_field = models.URLField(max_length=100)
|
||||||
|
custom_field = CustomField()
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
return 'method'
|
||||||
|
|
||||||
|
|
||||||
|
class RegularFieldsAndFKModel(models.Model):
|
||||||
|
"""
|
||||||
|
A model class for testing regular flat fields.
|
||||||
|
"""
|
||||||
|
auto_field = models.AutoField(primary_key=True)
|
||||||
|
big_integer_field = models.BigIntegerField()
|
||||||
|
boolean_field = models.BooleanField(default=False)
|
||||||
|
char_field = models.CharField(max_length=100)
|
||||||
|
comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=100)
|
||||||
|
date_field = models.DateField()
|
||||||
|
datetime_field = models.DateTimeField()
|
||||||
|
decimal_field = models.DecimalField(max_digits=3, decimal_places=1)
|
||||||
|
email_field = models.EmailField(max_length=100)
|
||||||
|
float_field = models.FloatField()
|
||||||
|
integer_field = models.IntegerField()
|
||||||
|
null_boolean_field = models.NullBooleanField()
|
||||||
|
positive_integer_field = models.PositiveIntegerField()
|
||||||
|
positive_small_integer_field = models.PositiveSmallIntegerField()
|
||||||
|
slug_field = models.SlugField(max_length=100)
|
||||||
|
small_integer_field = models.SmallIntegerField()
|
||||||
|
text_field = models.TextField()
|
||||||
|
time_field = models.TimeField()
|
||||||
|
url_field = models.URLField(max_length=100)
|
||||||
|
custom_field = CustomField()
|
||||||
|
fk = models.ForeignKey(RegularFieldsModel)
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
return 'method'
|
||||||
|
|
|
@ -6,13 +6,16 @@ These tests deal with ensuring that we correctly map the model fields onto
|
||||||
an appropriate set of serializer fields for each case.
|
an appropriate set of serializer fields for each case.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator, MinLengthValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator, MinLengthValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.compat import unicode_repr
|
from rest_framework.compat import unicode_repr
|
||||||
|
from .models import RegularFieldsModel
|
||||||
|
|
||||||
|
|
||||||
def dedent(blocktext):
|
def dedent(blocktext):
|
||||||
|
@ -22,46 +25,11 @@ def dedent(blocktext):
|
||||||
# Tests for regular field mappings.
|
# Tests for regular field mappings.
|
||||||
# ---------------------------------
|
# ---------------------------------
|
||||||
|
|
||||||
class CustomField(models.Field):
|
|
||||||
"""
|
|
||||||
A custom model field simply for testing purposes.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class OneFieldModel(models.Model):
|
class OneFieldModel(models.Model):
|
||||||
char_field = models.CharField(max_length=100)
|
char_field = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
class RegularFieldsModel(models.Model):
|
|
||||||
"""
|
|
||||||
A model class for testing regular flat fields.
|
|
||||||
"""
|
|
||||||
auto_field = models.AutoField(primary_key=True)
|
|
||||||
big_integer_field = models.BigIntegerField()
|
|
||||||
boolean_field = models.BooleanField(default=False)
|
|
||||||
char_field = models.CharField(max_length=100)
|
|
||||||
comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=100)
|
|
||||||
date_field = models.DateField()
|
|
||||||
datetime_field = models.DateTimeField()
|
|
||||||
decimal_field = models.DecimalField(max_digits=3, decimal_places=1)
|
|
||||||
email_field = models.EmailField(max_length=100)
|
|
||||||
float_field = models.FloatField()
|
|
||||||
integer_field = models.IntegerField()
|
|
||||||
null_boolean_field = models.NullBooleanField()
|
|
||||||
positive_integer_field = models.PositiveIntegerField()
|
|
||||||
positive_small_integer_field = models.PositiveSmallIntegerField()
|
|
||||||
slug_field = models.SlugField(max_length=100)
|
|
||||||
small_integer_field = models.SmallIntegerField()
|
|
||||||
text_field = models.TextField()
|
|
||||||
time_field = models.TimeField()
|
|
||||||
url_field = models.URLField(max_length=100)
|
|
||||||
custom_field = CustomField()
|
|
||||||
|
|
||||||
def method(self):
|
|
||||||
return 'method'
|
|
||||||
|
|
||||||
|
|
||||||
COLOR_CHOICES = (('red', 'Red'), ('blue', 'Blue'), ('green', 'Green'))
|
COLOR_CHOICES = (('red', 'Red'), ('blue', 'Blue'), ('green', 'Green'))
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,7 +93,7 @@ class TestRegularFieldMappings(TestCase):
|
||||||
text_field = CharField(style={'base_template': 'textarea.html'})
|
text_field = CharField(style={'base_template': 'textarea.html'})
|
||||||
time_field = TimeField()
|
time_field = TimeField()
|
||||||
url_field = URLField(max_length=100)
|
url_field = URLField(max_length=100)
|
||||||
custom_field = ModelField(model_field=<tests.test_model_serializer.CustomField: custom_field>)
|
custom_field = ModelField(model_field=<tests.fields.CustomField: custom_field>)
|
||||||
""")
|
""")
|
||||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||||
|
|
||||||
|
|
107
tests/test_serializers_benchmarks.py
Normal file
107
tests/test_serializers_benchmarks.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from pytest import mark
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
from .models import RegularFieldsModel, RegularFieldsAndFKModel
|
||||||
|
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'big_integer_field': 100000,
|
||||||
|
'char_field': 'a',
|
||||||
|
'comma_separated_integer_field': '1,2',
|
||||||
|
'date_field': datetime.now().date(),
|
||||||
|
'datetime_field': datetime.now(),
|
||||||
|
'decimal_field': Decimal('1.5'),
|
||||||
|
'email_field': 'somewhere@overtherainbow.com',
|
||||||
|
'float_field': 0.443,
|
||||||
|
'integer_field': 55,
|
||||||
|
'null_boolean_field': True,
|
||||||
|
'positive_integer_field': 1,
|
||||||
|
'positive_small_integer_field': 1,
|
||||||
|
'slug_field': 'slug-friendly-text',
|
||||||
|
'small_integer_field': 1,
|
||||||
|
'text_field': 'lorem ipsum',
|
||||||
|
'time_field': datetime.now().time(),
|
||||||
|
'url_field': 'https://overtherainbow.com'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = RegularFieldsModel
|
||||||
|
fields = data.keys() + ['method']
|
||||||
|
|
||||||
|
|
||||||
|
class TestNestedSerializer(serializers.ModelSerializer):
|
||||||
|
fk = TestSerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = RegularFieldsAndFKModel
|
||||||
|
fields = data.keys() + ['method', 'fk']
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_representation')
|
||||||
|
def test_object_serialization():
|
||||||
|
instance = RegularFieldsModel(**data)
|
||||||
|
serializer = TestSerializer(instance=instance)
|
||||||
|
|
||||||
|
assert serializer.data, serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_representation')
|
||||||
|
def test_nested_object_serialization():
|
||||||
|
nested_instance = RegularFieldsModel(**data)
|
||||||
|
instance = RegularFieldsAndFKModel(fk=nested_instance, **data)
|
||||||
|
serializer = TestSerializer(instance=instance)
|
||||||
|
|
||||||
|
assert serializer.data, serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_representation')
|
||||||
|
def test_object_list_serialization():
|
||||||
|
instance = [RegularFieldsModel(**data) for _ in range(100)]
|
||||||
|
serializer = TestSerializer(instance=instance, many=True)
|
||||||
|
|
||||||
|
assert serializer.data, serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_representation')
|
||||||
|
def test_object_serialization_with_partial_update():
|
||||||
|
instance = RegularFieldsModel(**data)
|
||||||
|
serializer = TestSerializer(instance=instance, data={'char_field': 'b'}, partial=True)
|
||||||
|
|
||||||
|
assert serializer.is_valid(), serializer.errors
|
||||||
|
assert serializer.data, serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_representation')
|
||||||
|
def test_object_serialization_with_update():
|
||||||
|
instance = RegularFieldsModel(**data)
|
||||||
|
new_data = data.copy()
|
||||||
|
new_data['char_field'] = 'b'
|
||||||
|
serializer = TestSerializer(instance=instance, data=new_data)
|
||||||
|
|
||||||
|
assert serializer.is_valid(), serializer.errors
|
||||||
|
assert serializer.data, serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_internal_value')
|
||||||
|
def test_object_deserialization():
|
||||||
|
serializer = TestSerializer(data=data)
|
||||||
|
|
||||||
|
assert serializer.is_valid(), serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.to_internal_value')
|
||||||
|
def test_object_list_deserialization():
|
||||||
|
serializer = TestSerializer(data=[data for _ in range(100)], many=True)
|
||||||
|
|
||||||
|
assert serializer.is_valid(), serializer.errors
|
||||||
|
|
||||||
|
|
||||||
|
@mark.bench('serializers.ModelSerializer.__init__')
|
||||||
|
def test_serializer_initialization():
|
||||||
|
TestSerializer(data=data)
|
1
tox.ini
1
tox.ini
|
@ -22,6 +22,7 @@ deps =
|
||||||
{py26,py27}-django{14,15}: django-oauth2-provider==0.2.3
|
{py26,py27}-django{14,15}: django-oauth2-provider==0.2.3
|
||||||
{py26,py27}-django16: django-oauth2-provider==0.2.4
|
{py26,py27}-django16: django-oauth2-provider==0.2.4
|
||||||
pytest-django==2.8.0
|
pytest-django==2.8.0
|
||||||
|
pytest-bench==0.3.0
|
||||||
django-filter==0.9.2
|
django-filter==0.9.2
|
||||||
defusedxml==0.3
|
defusedxml==0.3
|
||||||
markdown>=2.1.0
|
markdown>=2.1.0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user