2014-09-09 20:46:28 +04:00
"""
The ` ModelSerializer ` and ` HyperlinkedModelSerializer ` classes are essentially
shortcuts for automatically creating serializers based on a given model class .
These tests deal with ensuring that we correctly map the model fields onto
an appropriate set of serializer fields for each case .
"""
2018-04-24 10:24:05 +03:00
import datetime
2015-07-16 17:46:27 +03:00
import decimal
2020-09-03 13:47:11 +03:00
import json # noqa
2018-09-11 07:44:23 +03:00
import sys
2020-04-29 13:20:02 +03:00
import tempfile
2015-09-22 17:35:38 +03:00
from collections import OrderedDict
2015-07-16 17:46:27 +03:00
2017-02-22 14:06:48 +03:00
import pytest
2014-09-18 15:17:21 +04:00
from django . core . exceptions import ImproperlyConfigured
2019-05-24 14:47:35 +03:00
from django . core . serializers . json import DjangoJSONEncoder
2015-06-25 23:55:51 +03:00
from django . core . validators import (
MaxValueValidator , MinLengthValidator , MinValueValidator
)
2014-09-09 20:46:28 +04:00
from django . db import models
2019-06-22 11:14:15 +03:00
from django . db . models . signals import m2m_changed
from django . dispatch import receiver
2014-09-09 20:46:28 +04:00
from django . test import TestCase
2015-06-25 23:55:51 +03:00
2014-09-09 20:46:28 +04:00
from rest_framework import serializers
2019-04-30 18:53:44 +03:00
from rest_framework . compat import postgres_fields
2014-09-09 20:46:28 +04:00
2018-03-21 00:02:22 +03:00
from . models import NestedForeignKeySource
2014-09-09 20:46:28 +04:00
2014-09-15 16:38:28 +04:00
def dedent ( blocktext ) :
return ' \n ' . join ( [ line [ 12 : ] for line in blocktext . splitlines ( ) [ 1 : - 1 ] ] )
2014-09-23 17:15:00 +04:00
# Tests for regular field mappings.
# ---------------------------------
2014-09-09 20:46:28 +04:00
2014-09-18 16:07:38 +04:00
class CustomField ( models . Field ) :
2014-09-19 12:09:26 +04:00
"""
A custom model field simply for testing purposes .
"""
2014-09-18 16:07:38 +04:00
pass
2014-11-15 17:23:58 +03:00
class OneFieldModel ( models . Model ) :
char_field = models . CharField ( max_length = 100 )
2014-09-09 20:46:28 +04:00
class RegularFieldsModel ( models . Model ) :
2014-09-19 12:09:26 +04:00
"""
A model class for testing regular flat fields .
"""
2014-09-09 20:46:28 +04:00
auto_field = models . AutoField ( primary_key = True )
big_integer_field = models . BigIntegerField ( )
2014-09-11 16:20:44 +04:00
boolean_field = models . BooleanField ( default = False )
2014-09-09 20:46:28 +04:00
char_field = models . CharField ( max_length = 100 )
2014-10-02 23:41:18 +04:00
comma_separated_integer_field = models . CommaSeparatedIntegerField ( max_length = 100 )
2014-09-09 20:46:28 +04:00
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 ( )
2020-09-07 21:00:17 +03:00
null_boolean_field = models . BooleanField ( null = True , default = False )
2014-09-09 20:46:28 +04:00
positive_integer_field = models . PositiveIntegerField ( )
positive_small_integer_field = models . PositiveSmallIntegerField ( )
slug_field = models . SlugField ( max_length = 100 )
small_integer_field = models . SmallIntegerField ( )
2015-10-16 14:17:33 +03:00
text_field = models . TextField ( max_length = 100 )
2017-05-29 03:27:07 +03:00
file_field = models . FileField ( max_length = 100 )
2014-09-09 20:46:28 +04:00
time_field = models . TimeField ( )
url_field = models . URLField ( max_length = 100 )
2014-09-18 16:07:38 +04:00
custom_field = CustomField ( )
2020-04-29 13:20:02 +03:00
file_path_field = models . FilePathField ( path = tempfile . gettempdir ( ) )
2014-09-09 20:46:28 +04:00
2014-09-18 15:17:21 +04:00
def method ( self ) :
return ' method '
2014-09-09 20:46:28 +04:00
2014-09-23 17:15:00 +04:00
COLOR_CHOICES = ( ( ' red ' , ' Red ' ) , ( ' blue ' , ' Blue ' ) , ( ' green ' , ' Green ' ) )
2015-07-16 17:46:27 +03:00
DECIMAL_CHOICES = ( ( ' low ' , decimal . Decimal ( ' 0.1 ' ) ) , ( ' medium ' , decimal . Decimal ( ' 0.5 ' ) ) , ( ' high ' , decimal . Decimal ( ' 0.9 ' ) ) )
2014-09-23 17:15:00 +04:00
class FieldOptionsModel ( models . Model ) :
value_limit_field = models . IntegerField ( validators = [ MinValueValidator ( 1 ) , MaxValueValidator ( 10 ) ] )
length_limit_field = models . CharField ( validators = [ MinLengthValidator ( 3 ) ] , max_length = 12 )
blank_field = models . CharField ( blank = True , max_length = 10 )
null_field = models . IntegerField ( null = True )
default_field = models . IntegerField ( default = 0 )
descriptive_field = models . IntegerField ( help_text = ' Some help text ' , verbose_name = ' A label ' )
choices_field = models . CharField ( max_length = 100 , choices = COLOR_CHOICES )
2019-12-04 23:24:49 +03:00
text_choices_field = models . TextField ( choices = COLOR_CHOICES )
2014-09-23 17:15:00 +04:00
2015-07-16 18:18:14 +03:00
class ChoicesModel ( models . Model ) :
2015-07-16 18:01:50 +03:00
choices_field_with_nonstandard_args = models . DecimalField ( max_digits = 3 , decimal_places = 1 , choices = DECIMAL_CHOICES , verbose_name = ' A label ' )
2015-07-16 17:46:27 +03:00
2016-10-13 14:43:43 +03:00
class Issue3674ParentModel ( models . Model ) :
title = models . CharField ( max_length = 64 )
class Issue3674ChildModel ( models . Model ) :
2016-11-29 12:49:18 +03:00
parent = models . ForeignKey ( Issue3674ParentModel , related_name = ' children ' , on_delete = models . CASCADE )
2016-10-13 14:43:43 +03:00
value = models . CharField ( primary_key = True , max_length = 64 )
2017-03-28 09:20:55 +03:00
class UniqueChoiceModel ( models . Model ) :
CHOICES = (
( ' choice1 ' , ' choice 1 ' ) ,
( ' choice2 ' , ' choice 1 ' ) ,
)
name = models . CharField ( max_length = 254 , unique = True , choices = CHOICES )
2014-11-15 17:23:58 +03:00
class TestModelSerializer ( TestCase ) :
def test_create_method ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
non_model_field = serializers . CharField ( )
class Meta :
model = OneFieldModel
fields = ( ' char_field ' , ' non_model_field ' )
serializer = TestSerializer ( data = {
' char_field ' : ' foo ' ,
' non_model_field ' : ' bar ' ,
} )
serializer . is_valid ( )
2017-11-22 12:36:34 +03:00
2018-08-06 21:11:55 +03:00
msginitial = ' Got a `TypeError` when calling `OneFieldModel.objects.create()`. '
2017-11-22 12:36:34 +03:00
with self . assertRaisesMessage ( TypeError , msginitial ) :
serializer . save ( )
2014-11-15 17:23:58 +03:00
2015-03-23 18:01:19 +03:00
def test_abstract_model ( self ) :
"""
Test that trying to use ModelSerializer with Abstract Models
throws a ValueError exception .
"""
class AbstractModel ( models . Model ) :
afield = models . CharField ( max_length = 255 )
class Meta :
abstract = True
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = AbstractModel
fields = ( ' afield ' , )
serializer = TestSerializer ( data = {
' afield ' : ' foo ' ,
} )
2017-11-22 12:36:34 +03:00
2015-03-23 18:01:19 +03:00
msginitial = ' Cannot use ModelSerializer with Abstract Models. '
2017-11-22 12:36:34 +03:00
with self . assertRaisesMessage ( ValueError , msginitial ) :
serializer . is_valid ( )
2015-03-23 18:01:19 +03:00
2014-11-15 17:23:58 +03:00
2014-09-15 16:38:28 +04:00
class TestRegularFieldMappings ( TestCase ) :
def test_regular_fields ( self ) :
2014-09-18 16:07:38 +04:00
"""
2016-08-08 11:32:22 +03:00
Model fields should map to their equivalent serializer fields .
2014-09-18 16:07:38 +04:00
"""
2014-09-15 16:38:28 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RegularFieldsModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-15 16:38:28 +04:00
expected = dedent ( """
TestSerializer ( ) :
auto_field = IntegerField ( read_only = True )
big_integer_field = IntegerField ( )
2014-09-23 17:15:00 +04:00
boolean_field = BooleanField ( required = False )
2014-09-15 16:38:28 +04:00
char_field = CharField ( max_length = 100 )
2014-10-02 23:41:18 +04:00
comma_separated_integer_field = CharField ( max_length = 100 , validators = [ < django . core . validators . RegexValidator object > ] )
2014-09-15 16:38:28 +04:00
date_field = DateField ( )
datetime_field = DateTimeField ( )
decimal_field = DecimalField ( decimal_places = 1 , max_digits = 3 )
email_field = EmailField ( max_length = 100 )
float_field = FloatField ( )
integer_field = IntegerField ( )
2020-05-13 16:59:04 +03:00
null_boolean_field = BooleanField ( allow_null = True , required = False )
2014-09-15 16:38:28 +04:00
positive_integer_field = IntegerField ( )
positive_small_integer_field = IntegerField ( )
2018-12-19 17:37:52 +03:00
slug_field = SlugField ( allow_unicode = False , max_length = 100 )
2014-09-15 16:38:28 +04:00
small_integer_field = IntegerField ( )
2015-10-16 14:17:33 +03:00
text_field = CharField ( max_length = 100 , style = { ' base_template ' : ' textarea.html ' } )
2017-05-29 03:27:07 +03:00
file_field = FileField ( max_length = 100 )
2014-09-15 16:38:28 +04:00
time_field = TimeField ( )
url_field = URLField ( max_length = 100 )
2014-09-18 16:07:38 +04:00
custom_field = ModelField ( model_field = < tests . test_model_serializer . CustomField : custom_field > )
2020-04-29 13:20:02 +03:00
file_path_field = FilePathField ( path = % r )
""" % tempfile.gettempdir())
2015-10-16 14:17:33 +03:00
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-09 20:46:28 +04:00
2014-09-23 17:15:00 +04:00
def test_field_options ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = FieldOptionsModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-23 17:15:00 +04:00
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
value_limit_field = IntegerField ( max_value = 10 , min_value = 1 )
length_limit_field = CharField ( max_length = 12 , min_length = 3 )
2014-11-13 22:28:57 +03:00
blank_field = CharField ( allow_blank = True , max_length = 10 , required = False )
null_field = IntegerField ( allow_null = True , required = False )
2014-09-23 17:15:00 +04:00
default_field = IntegerField ( required = False )
descriptive_field = IntegerField ( help_text = ' Some help text ' , label = ' A label ' )
2015-08-06 13:43:03 +03:00
choices_field = ChoiceField ( choices = ( ( ' red ' , ' Red ' ) , ( ' blue ' , ' Blue ' ) , ( ' green ' , ' Green ' ) ) )
2019-12-04 23:24:49 +03:00
text_choices_field = ChoiceField ( choices = ( ( ' red ' , ' Red ' ) , ( ' blue ' , ' Blue ' ) , ( ' green ' , ' Green ' ) ) )
2014-09-23 17:15:00 +04:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-23 17:15:00 +04:00
2020-05-13 16:59:04 +03:00
def test_nullable_boolean_field_choices ( self ) :
class NullableBooleanChoicesModel ( models . Model ) :
CHECKLIST_OPTIONS = (
( None , ' Unknown ' ) ,
( True , ' Yes ' ) ,
( False , ' No ' ) ,
)
field = models . BooleanField ( null = True , choices = CHECKLIST_OPTIONS )
class NullableBooleanChoicesSerializer ( serializers . ModelSerializer ) :
class Meta :
model = NullableBooleanChoicesModel
fields = [ ' field ' ]
serializer = NullableBooleanChoicesSerializer ( data = dict (
field = None ,
) )
self . assertTrue ( serializer . is_valid ( ) )
self . assertEqual ( serializer . errors , { } )
2014-09-18 15:17:21 +04:00
def test_method_field ( self ) :
"""
Properties and methods on the model should be allowed as ` Meta . fields `
values , and should map to ` ReadOnlyField ` .
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RegularFieldsModel
fields = ( ' auto_field ' , ' method ' )
expected = dedent ( """
TestSerializer ( ) :
auto_field = IntegerField ( read_only = True )
method = ReadOnlyField ( )
""" )
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
def test_pk_fields ( self ) :
"""
Both ` pk ` and the actual primary key name are valid in ` Meta . fields ` .
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RegularFieldsModel
fields = ( ' pk ' , ' auto_field ' )
expected = dedent ( """
TestSerializer ( ) :
pk = IntegerField ( label = ' Auto field ' , read_only = True )
auto_field = IntegerField ( read_only = True )
""" )
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
def test_extra_field_kwargs ( self ) :
"""
Ensure ` extra_kwargs ` are passed to generated fields .
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RegularFieldsModel
2014-09-19 12:09:26 +04:00
fields = ( ' auto_field ' , ' char_field ' )
2014-09-18 15:17:21 +04:00
extra_kwargs = { ' char_field ' : { ' default ' : ' extra ' } }
expected = dedent ( """
TestSerializer ( ) :
2014-09-19 12:09:26 +04:00
auto_field = IntegerField ( read_only = True )
2014-09-18 15:17:21 +04:00
char_field = CharField ( default = ' extra ' , max_length = 100 )
""" )
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2015-07-01 17:10:18 +03:00
def test_extra_field_kwargs_required ( self ) :
"""
Ensure ` extra_kwargs ` are passed to generated fields .
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RegularFieldsModel
fields = ( ' auto_field ' , ' char_field ' )
extra_kwargs = { ' auto_field ' : { ' required ' : False , ' read_only ' : False } }
expected = dedent ( """
TestSerializer ( ) :
auto_field = IntegerField ( read_only = False , required = False )
char_field = CharField ( max_length = 100 )
""" )
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-18 15:17:21 +04:00
def test_invalid_field ( self ) :
"""
Field names that do not map to a model field or relationship should
2019-07-25 20:04:01 +03:00
raise a configuration error .
2014-09-18 15:17:21 +04:00
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RegularFieldsModel
fields = ( ' auto_field ' , ' invalid ' )
2014-12-20 00:32:43 +03:00
expected = ' Field name `invalid` is not valid for model `RegularFieldsModel`. '
2017-11-22 12:36:34 +03:00
with self . assertRaisesMessage ( ImproperlyConfigured , expected ) :
TestSerializer ( ) . fields
2014-09-18 15:17:21 +04:00
def test_missing_field ( self ) :
2014-09-18 16:07:38 +04:00
"""
Fields that have been declared on the serializer class must be included
in the ` Meta . fields ` if it exists .
"""
2014-09-18 15:17:21 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
missing = serializers . ReadOnlyField ( )
class Meta :
model = RegularFieldsModel
fields = ( ' auto_field ' , )
expected = (
2014-12-19 15:18:40 +03:00
" The field ' missing ' was declared on serializer TestSerializer, "
" but has not been included in the ' fields ' option. "
2014-09-18 15:17:21 +04:00
)
2017-11-22 12:36:34 +03:00
with self . assertRaisesMessage ( AssertionError , expected ) :
TestSerializer ( ) . fields
2014-09-18 15:17:21 +04:00
2015-01-21 16:03:37 +03:00
def test_missing_superclass_field ( self ) :
"""
Fields that have been declared on a parent of the serializer class may
be excluded from the ` Meta . fields ` option .
"""
class TestSerializer ( serializers . ModelSerializer ) :
missing = serializers . ReadOnlyField ( )
class ChildSerializer ( TestSerializer ) :
class Meta :
model = RegularFieldsModel
fields = ( ' auto_field ' , )
ChildSerializer ( ) . fields
2015-07-16 17:46:27 +03:00
def test_choices_with_nonstandard_args ( self ) :
class ExampleSerializer ( serializers . ModelSerializer ) :
class Meta :
2015-07-16 18:18:14 +03:00
model = ChoicesModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-07-16 17:46:27 +03:00
ExampleSerializer ( )
2014-09-09 20:46:28 +04:00
2015-06-01 19:20:53 +03:00
class TestDurationFieldMapping ( TestCase ) :
def test_duration_field ( self ) :
class DurationFieldModel ( models . Model ) :
"""
A model that defines DurationField .
"""
2018-04-24 10:24:05 +03:00
duration_field = models . DurationField ( )
2015-06-01 19:20:53 +03:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = DurationFieldModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-06-01 19:20:53 +03:00
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
duration_field = DurationField ( )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2015-06-01 19:20:53 +03:00
2018-04-24 10:24:05 +03:00
def test_duration_field_with_validators ( self ) :
class ValidatedDurationFieldModel ( models . Model ) :
"""
A model that defines DurationField with validators .
"""
duration_field = models . DurationField (
validators = [ MinValueValidator ( datetime . timedelta ( days = 1 ) ) , MaxValueValidator ( datetime . timedelta ( days = 3 ) ) ]
)
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = ValidatedDurationFieldModel
fields = ' __all__ '
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
duration_field = DurationField ( max_value = datetime . timedelta ( 3 ) , min_value = datetime . timedelta ( 1 ) )
2018-09-11 07:44:23 +03:00
""" ) if sys.version_info < (3, 7) else dedent( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
duration_field = DurationField ( max_value = datetime . timedelta ( days = 3 ) , min_value = datetime . timedelta ( days = 1 ) )
2018-04-24 10:24:05 +03:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2018-04-24 10:24:05 +03:00
2015-06-01 19:20:53 +03:00
2015-08-08 02:53:43 +03:00
class TestGenericIPAddressFieldValidation ( TestCase ) :
def test_ip_address_validation ( self ) :
class IPAddressFieldModel ( models . Model ) :
address = models . GenericIPAddressField ( )
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = IPAddressFieldModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-08-08 02:53:43 +03:00
s = TestSerializer ( data = { ' address ' : ' not an ip address ' } )
self . assertFalse ( s . is_valid ( ) )
2016-07-13 16:40:42 +03:00
self . assertEqual ( 1 , len ( s . errors [ ' address ' ] ) ,
' Unexpected number of validation errors: '
2019-04-30 18:53:44 +03:00
' {} ' . format ( s . errors ) )
2015-08-08 02:53:43 +03:00
2018-05-03 15:31:46 +03:00
@pytest.mark.skipif ( ' not postgres_fields ' )
2018-01-15 17:52:30 +03:00
class TestPosgresFieldsMapping ( TestCase ) :
def test_hstore_field ( self ) :
class HStoreFieldModel ( models . Model ) :
hstore_field = postgres_fields . HStoreField ( )
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = HStoreFieldModel
fields = [ ' hstore_field ' ]
expected = dedent ( """
TestSerializer ( ) :
hstore_field = HStoreField ( )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2018-01-15 17:52:30 +03:00
def test_array_field ( self ) :
class ArrayFieldModel ( models . Model ) :
array_field = postgres_fields . ArrayField ( base_field = models . CharField ( ) )
2019-07-02 03:34:34 +03:00
array_field_with_blank = postgres_fields . ArrayField ( blank = True , base_field = models . CharField ( ) )
2018-01-15 17:52:30 +03:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = ArrayFieldModel
2019-07-02 03:34:34 +03:00
fields = [ ' array_field ' , ' array_field_with_blank ' ]
2018-01-15 17:52:30 +03:00
expected = dedent ( """
TestSerializer ( ) :
2019-07-02 03:34:34 +03:00
array_field = ListField ( allow_empty = False , child = CharField ( label = ' Array field ' , validators = [ < django . core . validators . MaxLengthValidator object > ] ) )
array_field_with_blank = ListField ( child = CharField ( label = ' Array field with blank ' , validators = [ < django . core . validators . MaxLengthValidator object > ] ) , required = False )
2018-01-15 17:52:30 +03:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2018-01-15 17:52:30 +03:00
2020-09-03 13:47:11 +03:00
@pytest.mark.skipif ( hasattr ( models , ' JSONField ' ) , reason = ' has models.JSONField ' )
2018-01-15 17:52:30 +03:00
def test_json_field ( self ) :
class JSONFieldModel ( models . Model ) :
json_field = postgres_fields . JSONField ( )
2019-05-24 14:47:35 +03:00
json_field_with_encoder = postgres_fields . JSONField ( encoder = DjangoJSONEncoder )
2018-01-15 17:52:30 +03:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = JSONFieldModel
2019-05-24 14:47:35 +03:00
fields = [ ' json_field ' , ' json_field_with_encoder ' ]
2018-01-15 17:52:30 +03:00
expected = dedent ( """
TestSerializer ( ) :
2019-05-24 14:47:35 +03:00
json_field = JSONField ( encoder = None , style = { ' base_template ' : ' textarea.html ' } )
json_field_with_encoder = JSONField ( encoder = < class ' django . core . serializers . json . DjangoJSONEncoder ' >, style= { ' base_template ' : ' textarea . html ' })
2020-09-03 13:47:11 +03:00
""" )
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
class CustomJSONDecoder ( json . JSONDecoder ) :
pass
@pytest.mark.skipif ( not hasattr ( models , ' JSONField ' ) , reason = ' no models.JSONField ' )
class TestDjangoJSONFieldMapping ( TestCase ) :
def test_json_field ( self ) :
class JSONFieldModel ( models . Model ) :
json_field = models . JSONField ( )
json_field_with_encoder = models . JSONField ( encoder = DjangoJSONEncoder , decoder = CustomJSONDecoder )
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = JSONFieldModel
fields = [ ' json_field ' , ' json_field_with_encoder ' ]
expected = dedent ( """
TestSerializer ( ) :
json_field = JSONField ( decoder = None , encoder = None , style = { ' base_template ' : ' textarea.html ' } )
json_field_with_encoder = JSONField ( decoder = < class ' tests . test_model_serializer . CustomJSONDecoder ' >, encoder=<class ' django . core . serializers . json . DjangoJSONEncoder ' >, style= { ' base_template ' : ' textarea . html ' })
2018-01-15 17:52:30 +03:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2018-01-15 17:52:30 +03:00
2014-09-23 17:15:00 +04:00
# Tests for relational field mappings.
# ------------------------------------
2014-09-09 20:46:28 +04:00
2014-09-11 16:20:44 +04:00
class ForeignKeyTargetModel ( models . Model ) :
name = models . CharField ( max_length = 100 )
2014-09-09 20:46:28 +04:00
2014-09-11 16:20:44 +04:00
class ManyToManyTargetModel ( models . Model ) :
name = models . CharField ( max_length = 100 )
2014-09-09 20:46:28 +04:00
2014-09-11 16:20:44 +04:00
class OneToOneTargetModel ( models . Model ) :
name = models . CharField ( max_length = 100 )
2014-09-09 20:46:28 +04:00
2014-09-15 17:05:58 +04:00
class ThroughTargetModel ( models . Model ) :
name = models . CharField ( max_length = 100 )
class Supplementary ( models . Model ) :
extra = models . IntegerField ( )
2016-06-02 16:39:10 +03:00
forwards = models . ForeignKey ( ' ThroughTargetModel ' , on_delete = models . CASCADE )
backwards = models . ForeignKey ( ' RelationalModel ' , on_delete = models . CASCADE )
2014-09-15 17:05:58 +04:00
2014-09-09 20:46:28 +04:00
class RelationalModel ( models . Model ) :
2016-06-02 16:39:10 +03:00
foreign_key = models . ForeignKey ( ForeignKeyTargetModel , related_name = ' reverse_foreign_key ' , on_delete = models . CASCADE )
2014-09-13 00:32:20 +04:00
many_to_many = models . ManyToManyField ( ManyToManyTargetModel , related_name = ' reverse_many_to_many ' )
2016-06-02 16:39:10 +03:00
one_to_one = models . OneToOneField ( OneToOneTargetModel , related_name = ' reverse_one_to_one ' , on_delete = models . CASCADE )
2014-09-15 17:05:58 +04:00
through = models . ManyToManyField ( ThroughTargetModel , through = Supplementary , related_name = ' reverse_through ' )
2014-09-09 20:46:28 +04:00
2015-05-28 05:06:57 +03:00
class UniqueTogetherModel ( models . Model ) :
2016-06-02 16:39:10 +03:00
foreign_key = models . ForeignKey ( ForeignKeyTargetModel , related_name = ' unique_foreign_key ' , on_delete = models . CASCADE )
one_to_one = models . OneToOneField ( OneToOneTargetModel , related_name = ' unique_one_to_one ' , on_delete = models . CASCADE )
2015-05-28 16:29:15 +03:00
2015-05-28 05:06:57 +03:00
class Meta :
unique_together = ( " foreign_key " , " one_to_one " )
2014-09-15 16:38:28 +04:00
class TestRelationalFieldMappings ( TestCase ) :
2014-09-18 17:23:00 +04:00
def test_pk_relations ( self ) :
2014-09-09 20:46:28 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RelationalModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-15 16:38:28 +04:00
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
foreign_key = PrimaryKeyRelatedField ( queryset = ForeignKeyTargetModel . objects . all ( ) )
2014-10-07 20:04:53 +04:00
one_to_one = PrimaryKeyRelatedField ( queryset = OneToOneTargetModel . objects . all ( ) , validators = [ < UniqueValidator ( queryset = RelationalModel . objects . all ( ) ) > ] )
2015-07-30 19:03:08 +03:00
many_to_many = PrimaryKeyRelatedField ( allow_empty = False , many = True , queryset = ManyToManyTargetModel . objects . all ( ) )
2014-09-15 17:05:58 +04:00
through = PrimaryKeyRelatedField ( many = True , read_only = True )
2014-09-15 16:38:28 +04:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-09 20:46:28 +04:00
2014-09-18 17:23:00 +04:00
def test_nested_relations ( self ) :
2014-09-09 20:46:28 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RelationalModel
depth = 1
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-15 16:38:28 +04:00
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
2014-09-18 14:20:56 +04:00
foreign_key = NestedSerializer ( read_only = True ) :
2014-09-15 16:38:28 +04:00
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
2014-09-18 14:20:56 +04:00
one_to_one = NestedSerializer ( read_only = True ) :
2014-09-15 16:38:28 +04:00
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
2014-09-18 14:20:56 +04:00
many_to_many = NestedSerializer ( many = True , read_only = True ) :
2014-09-15 16:38:28 +04:00
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
2014-09-18 14:20:56 +04:00
through = NestedSerializer ( many = True , read_only = True ) :
2014-09-15 17:05:58 +04:00
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
2014-09-15 16:38:28 +04:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-09 20:46:28 +04:00
2014-09-18 17:23:00 +04:00
def test_hyperlinked_relations ( self ) :
2014-09-09 20:46:28 +04:00
class TestSerializer ( serializers . HyperlinkedModelSerializer ) :
class Meta :
model = RelationalModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-15 16:38:28 +04:00
expected = dedent ( """
TestSerializer ( ) :
url = HyperlinkedIdentityField ( view_name = ' relationalmodel-detail ' )
foreign_key = HyperlinkedRelatedField ( queryset = ForeignKeyTargetModel . objects . all ( ) , view_name = ' foreignkeytargetmodel-detail ' )
2014-10-07 20:04:53 +04:00
one_to_one = HyperlinkedRelatedField ( queryset = OneToOneTargetModel . objects . all ( ) , validators = [ < UniqueValidator ( queryset = RelationalModel . objects . all ( ) ) > ] , view_name = ' onetoonetargetmodel-detail ' )
2015-07-30 19:03:08 +03:00
many_to_many = HyperlinkedRelatedField ( allow_empty = False , many = True , queryset = ManyToManyTargetModel . objects . all ( ) , view_name = ' manytomanytargetmodel-detail ' )
2014-09-15 17:05:58 +04:00
through = HyperlinkedRelatedField ( many = True , read_only = True , view_name = ' throughtargetmodel-detail ' )
2014-09-15 16:38:28 +04:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-09 20:46:28 +04:00
2014-09-18 17:23:00 +04:00
def test_nested_hyperlinked_relations ( self ) :
2014-09-09 20:46:28 +04:00
class TestSerializer ( serializers . HyperlinkedModelSerializer ) :
class Meta :
model = RelationalModel
depth = 1
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-15 16:38:28 +04:00
expected = dedent ( """
TestSerializer ( ) :
url = HyperlinkedIdentityField ( view_name = ' relationalmodel-detail ' )
2014-09-18 14:20:56 +04:00
foreign_key = NestedSerializer ( read_only = True ) :
2014-09-15 16:55:09 +04:00
url = HyperlinkedIdentityField ( view_name = ' foreignkeytargetmodel-detail ' )
2014-09-15 16:38:28 +04:00
name = CharField ( max_length = 100 )
2014-09-18 14:20:56 +04:00
one_to_one = NestedSerializer ( read_only = True ) :
2014-09-15 16:55:09 +04:00
url = HyperlinkedIdentityField ( view_name = ' onetoonetargetmodel-detail ' )
2014-09-15 16:38:28 +04:00
name = CharField ( max_length = 100 )
2014-09-18 14:20:56 +04:00
many_to_many = NestedSerializer ( many = True , read_only = True ) :
2014-09-15 16:55:09 +04:00
url = HyperlinkedIdentityField ( view_name = ' manytomanytargetmodel-detail ' )
2014-09-15 16:38:28 +04:00
name = CharField ( max_length = 100 )
2014-09-18 14:20:56 +04:00
through = NestedSerializer ( many = True , read_only = True ) :
2014-09-15 17:05:58 +04:00
url = HyperlinkedIdentityField ( view_name = ' throughtargetmodel-detail ' )
name = CharField ( max_length = 100 )
2014-09-15 16:48:03 +04:00
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-15 16:48:03 +04:00
2017-05-16 13:10:43 +03:00
def test_nested_hyperlinked_relations_starred_source ( self ) :
2017-05-16 13:02:23 +03:00
class TestSerializer ( serializers . HyperlinkedModelSerializer ) :
class Meta :
model = RelationalModel
depth = 1
fields = ' __all__ '
extra_kwargs = {
' url ' : {
' source ' : ' * ' ,
} }
expected = dedent ( """
TestSerializer ( ) :
url = HyperlinkedIdentityField ( source = ' * ' , view_name = ' relationalmodel-detail ' )
foreign_key = NestedSerializer ( read_only = True ) :
url = HyperlinkedIdentityField ( view_name = ' foreignkeytargetmodel-detail ' )
name = CharField ( max_length = 100 )
one_to_one = NestedSerializer ( read_only = True ) :
url = HyperlinkedIdentityField ( view_name = ' onetoonetargetmodel-detail ' )
name = CharField ( max_length = 100 )
many_to_many = NestedSerializer ( many = True , read_only = True ) :
url = HyperlinkedIdentityField ( view_name = ' manytomanytargetmodel-detail ' )
name = CharField ( max_length = 100 )
through = NestedSerializer ( many = True , read_only = True ) :
url = HyperlinkedIdentityField ( view_name = ' throughtargetmodel-detail ' )
name = CharField ( max_length = 100 )
""" )
self . maxDiff = None
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2017-05-16 13:02:23 +03:00
2015-05-28 05:06:57 +03:00
def test_nested_unique_together_relations ( self ) :
class TestSerializer ( serializers . HyperlinkedModelSerializer ) :
class Meta :
model = UniqueTogetherModel
depth = 1
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-05-28 05:06:57 +03:00
expected = dedent ( """
TestSerializer ( ) :
url = HyperlinkedIdentityField ( view_name = ' uniquetogethermodel-detail ' )
foreign_key = NestedSerializer ( read_only = True ) :
url = HyperlinkedIdentityField ( view_name = ' foreignkeytargetmodel-detail ' )
name = CharField ( max_length = 100 )
one_to_one = NestedSerializer ( read_only = True ) :
url = HyperlinkedIdentityField ( view_name = ' onetoonetargetmodel-detail ' )
name = CharField ( max_length = 100 )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2015-05-28 05:06:57 +03:00
2014-09-18 17:23:00 +04:00
def test_pk_reverse_foreign_key ( self ) :
2014-09-15 16:48:03 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = ForeignKeyTargetModel
fields = ( ' id ' , ' name ' , ' reverse_foreign_key ' )
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
reverse_foreign_key = PrimaryKeyRelatedField ( many = True , queryset = RelationalModel . objects . all ( ) )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-13 00:32:20 +04:00
2014-09-18 17:23:00 +04:00
def test_pk_reverse_one_to_one ( self ) :
2014-09-15 16:48:03 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = OneToOneTargetModel
fields = ( ' id ' , ' name ' , ' reverse_one_to_one ' )
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
reverse_one_to_one = PrimaryKeyRelatedField ( queryset = RelationalModel . objects . all ( ) )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-15 16:48:03 +04:00
2014-09-18 17:23:00 +04:00
def test_pk_reverse_many_to_many ( self ) :
2014-09-15 16:48:03 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = ManyToManyTargetModel
fields = ( ' id ' , ' name ' , ' reverse_many_to_many ' )
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
reverse_many_to_many = PrimaryKeyRelatedField ( many = True , queryset = RelationalModel . objects . all ( ) )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-15 17:05:58 +04:00
2014-09-18 17:23:00 +04:00
def test_pk_reverse_through ( self ) :
2014-09-15 17:05:58 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = ThroughTargetModel
fields = ( ' id ' , ' name ' , ' reverse_through ' )
expected = dedent ( """
TestSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
name = CharField ( max_length = 100 )
reverse_through = PrimaryKeyRelatedField ( many = True , read_only = True )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2014-09-18 17:23:00 +04:00
2015-08-10 14:19:46 +03:00
class DisplayValueTargetModel ( models . Model ) :
name = models . CharField ( max_length = 100 )
def __str__ ( self ) :
return ' %s Color ' % ( self . name )
class DisplayValueModel ( models . Model ) :
2016-06-02 16:39:10 +03:00
color = models . ForeignKey ( DisplayValueTargetModel , on_delete = models . CASCADE )
2015-08-10 14:19:46 +03:00
class TestRelationalFieldDisplayValue ( TestCase ) :
def setUp ( self ) :
DisplayValueTargetModel . objects . bulk_create ( [
DisplayValueTargetModel ( name = ' Red ' ) ,
DisplayValueTargetModel ( name = ' Yellow ' ) ,
DisplayValueTargetModel ( name = ' Green ' ) ,
] )
def test_default_display_value ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = DisplayValueModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-08-10 14:19:46 +03:00
serializer = TestSerializer ( )
2016-08-10 18:38:59 +03:00
expected = OrderedDict ( [ ( 1 , ' Red Color ' ) , ( 2 , ' Yellow Color ' ) , ( 3 , ' Green Color ' ) ] )
2015-08-10 14:19:46 +03:00
self . assertEqual ( serializer . fields [ ' color ' ] . choices , expected )
def test_custom_display_value ( self ) :
class TestField ( serializers . PrimaryKeyRelatedField ) :
def display_value ( self , instance ) :
return ' My %s Color ' % ( instance . name )
class TestSerializer ( serializers . ModelSerializer ) :
color = TestField ( queryset = DisplayValueTargetModel . objects . all ( ) )
class Meta :
model = DisplayValueModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-08-10 14:19:46 +03:00
serializer = TestSerializer ( )
2016-08-10 18:38:59 +03:00
expected = OrderedDict ( [ ( 1 , ' My Red Color ' ) , ( 2 , ' My Yellow Color ' ) , ( 3 , ' My Green Color ' ) ] )
2015-08-10 14:19:46 +03:00
self . assertEqual ( serializer . fields [ ' color ' ] . choices , expected )
2014-09-18 17:23:00 +04:00
class TestIntegration ( TestCase ) :
def setUp ( self ) :
self . foreign_key_target = ForeignKeyTargetModel . objects . create (
name = ' foreign_key '
)
self . one_to_one_target = OneToOneTargetModel . objects . create (
name = ' one_to_one '
)
self . many_to_many_targets = [
ManyToManyTargetModel . objects . create (
name = ' many_to_many ( %d ) ' % idx
) for idx in range ( 3 )
]
self . instance = RelationalModel . objects . create (
foreign_key = self . foreign_key_target ,
one_to_one = self . one_to_one_target ,
)
2017-10-05 21:41:38 +03:00
self . instance . many_to_many . set ( self . many_to_many_targets )
2014-09-18 17:23:00 +04:00
2014-09-19 12:09:26 +04:00
def test_pk_retrival ( self ) :
2014-09-18 17:23:00 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RelationalModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-18 17:23:00 +04:00
2014-09-19 12:09:26 +04:00
serializer = TestSerializer ( self . instance )
2014-09-18 17:23:00 +04:00
expected = {
' id ' : self . instance . pk ,
' foreign_key ' : self . foreign_key_target . pk ,
' one_to_one ' : self . one_to_one_target . pk ,
' many_to_many ' : [ item . pk for item in self . many_to_many_targets ] ,
' through ' : [ ]
}
self . assertEqual ( serializer . data , expected )
2014-09-18 17:58:08 +04:00
def test_pk_create ( self ) :
2014-09-19 12:09:26 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RelationalModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-19 12:09:26 +04:00
2014-09-18 17:58:08 +04:00
new_foreign_key = ForeignKeyTargetModel . objects . create (
name = ' foreign_key '
)
new_one_to_one = OneToOneTargetModel . objects . create (
name = ' one_to_one '
)
new_many_to_many = [
ManyToManyTargetModel . objects . create (
name = ' new many_to_many ( %d ) ' % idx
) for idx in range ( 3 )
]
data = {
' foreign_key ' : new_foreign_key . pk ,
' one_to_one ' : new_one_to_one . pk ,
' many_to_many ' : [ item . pk for item in new_many_to_many ] ,
}
# Serializer should validate okay.
2014-09-19 12:09:26 +04:00
serializer = TestSerializer ( data = data )
2014-09-18 17:58:08 +04:00
assert serializer . is_valid ( )
# Creating the instance, relationship attributes should be set.
instance = serializer . save ( )
assert instance . foreign_key . pk == new_foreign_key . pk
assert instance . one_to_one . pk == new_one_to_one . pk
assert [
item . pk for item in instance . many_to_many . all ( )
] == [
item . pk for item in new_many_to_many
]
assert list ( instance . through . all ( ) ) == [ ]
# Representation should be correct.
expected = {
' id ' : instance . pk ,
' foreign_key ' : new_foreign_key . pk ,
' one_to_one ' : new_one_to_one . pk ,
' many_to_many ' : [ item . pk for item in new_many_to_many ] ,
' through ' : [ ]
}
self . assertEqual ( serializer . data , expected )
2014-09-18 18:47:27 +04:00
def test_pk_update ( self ) :
2014-09-19 12:09:26 +04:00
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = RelationalModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2014-09-19 12:09:26 +04:00
2014-09-18 18:47:27 +04:00
new_foreign_key = ForeignKeyTargetModel . objects . create (
name = ' foreign_key '
)
new_one_to_one = OneToOneTargetModel . objects . create (
name = ' one_to_one '
)
new_many_to_many = [
ManyToManyTargetModel . objects . create (
name = ' new many_to_many ( %d ) ' % idx
) for idx in range ( 3 )
]
data = {
' foreign_key ' : new_foreign_key . pk ,
' one_to_one ' : new_one_to_one . pk ,
' many_to_many ' : [ item . pk for item in new_many_to_many ] ,
}
# Serializer should validate okay.
2014-09-19 12:09:26 +04:00
serializer = TestSerializer ( self . instance , data = data )
2014-09-18 18:47:27 +04:00
assert serializer . is_valid ( )
# Creating the instance, relationship attributes should be set.
instance = serializer . save ( )
assert instance . foreign_key . pk == new_foreign_key . pk
assert instance . one_to_one . pk == new_one_to_one . pk
assert [
item . pk for item in instance . many_to_many . all ( )
] == [
item . pk for item in new_many_to_many
]
assert list ( instance . through . all ( ) ) == [ ]
# Representation should be correct.
expected = {
' id ' : self . instance . pk ,
' foreign_key ' : new_foreign_key . pk ,
' one_to_one ' : new_one_to_one . pk ,
' many_to_many ' : [ item . pk for item in new_many_to_many ] ,
' through ' : [ ]
}
self . assertEqual ( serializer . data , expected )
2014-09-19 19:43:13 +04:00
# Tests for bulk create using `ListSerializer`.
class BulkCreateModel ( models . Model ) :
name = models . CharField ( max_length = 10 )
class TestBulkCreate ( TestCase ) :
def test_bulk_create ( self ) :
class BasicModelSerializer ( serializers . ModelSerializer ) :
class Meta :
model = BulkCreateModel
fields = ( ' name ' , )
class BulkCreateSerializer ( serializers . ListSerializer ) :
child = BasicModelSerializer ( )
data = [ { ' name ' : ' a ' } , { ' name ' : ' b ' } , { ' name ' : ' c ' } ]
serializer = BulkCreateSerializer ( data = data )
assert serializer . is_valid ( )
# Objects are returned by save().
instances = serializer . save ( )
assert len ( instances ) == 3
assert [ item . name for item in instances ] == [ ' a ' , ' b ' , ' c ' ]
# Objects have been created in the database.
assert BulkCreateModel . objects . count ( ) == 3
assert list ( BulkCreateModel . objects . values_list ( ' name ' , flat = True ) ) == [ ' a ' , ' b ' , ' c ' ]
# Serializer returns correct data.
assert serializer . data == data
2014-12-05 17:15:58 +03:00
2016-04-11 16:13:11 +03:00
class MetaClassTestModel ( models . Model ) :
2014-12-05 17:15:58 +03:00
text = models . CharField ( max_length = 100 )
class TestSerializerMetaClass ( TestCase ) :
def test_meta_class_fields_option ( self ) :
class ExampleSerializer ( serializers . ModelSerializer ) :
class Meta :
2016-04-11 16:13:11 +03:00
model = MetaClassTestModel
2014-12-05 17:15:58 +03:00
fields = ' text '
2017-11-22 12:36:34 +03:00
msginitial = " The `fields` option must be a list or tuple "
with self . assertRaisesMessage ( TypeError , msginitial ) :
2014-12-05 17:15:58 +03:00
ExampleSerializer ( ) . fields
def test_meta_class_exclude_option ( self ) :
class ExampleSerializer ( serializers . ModelSerializer ) :
class Meta :
2016-04-11 16:13:11 +03:00
model = MetaClassTestModel
2014-12-05 17:15:58 +03:00
exclude = ' text '
2017-11-22 12:36:34 +03:00
msginitial = " The `exclude` option must be a list or tuple "
with self . assertRaisesMessage ( TypeError , msginitial ) :
2014-12-05 17:15:58 +03:00
ExampleSerializer ( ) . fields
def test_meta_class_fields_and_exclude_options ( self ) :
class ExampleSerializer ( serializers . ModelSerializer ) :
class Meta :
2016-04-11 16:13:11 +03:00
model = MetaClassTestModel
2014-12-05 17:15:58 +03:00
fields = ( ' text ' , )
exclude = ( ' text ' , )
2017-11-22 12:36:34 +03:00
msginitial = " Cannot set both ' fields ' and ' exclude ' options on serializer ExampleSerializer. "
with self . assertRaisesMessage ( AssertionError , msginitial ) :
2014-12-05 17:15:58 +03:00
ExampleSerializer ( ) . fields
2017-11-20 11:51:16 +03:00
def test_declared_fields_with_exclude_option ( self ) :
class ExampleSerializer ( serializers . ModelSerializer ) :
text = serializers . CharField ( )
class Meta :
model = MetaClassTestModel
exclude = ( ' text ' , )
expected = (
" Cannot both declare the field ' text ' and include it in the "
" ExampleSerializer ' exclude ' option. Remove the field or, if "
" inherited from a parent serializer, disable with `text = None`. "
)
with self . assertRaisesMessage ( AssertionError , expected ) :
ExampleSerializer ( ) . fields
2015-06-25 05:02:28 +03:00
class Issue2704TestCase ( TestCase ) :
def test_queryset_all ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
additional_attr = serializers . CharField ( )
class Meta :
model = OneFieldModel
fields = ( ' char_field ' , ' additional_attr ' )
OneFieldModel . objects . create ( char_field = ' abc ' )
qs = OneFieldModel . objects . all ( )
for o in qs :
o . additional_attr = ' 123 '
serializer = TestSerializer ( instance = qs , many = True )
expected = [ {
' char_field ' : ' abc ' ,
' additional_attr ' : ' 123 ' ,
} ]
assert serializer . data == expected
2015-10-30 14:47:11 +03:00
class DecimalFieldModel ( models . Model ) :
decimal_field = models . DecimalField (
max_digits = 3 ,
decimal_places = 1 ,
validators = [ MinValueValidator ( 1 ) , MaxValueValidator ( 3 ) ]
)
class TestDecimalFieldMappings ( TestCase ) :
def test_decimal_field_has_decimal_validator ( self ) :
"""
2015-12-28 18:38:53 +03:00
Test that a ` DecimalField ` has no ` DecimalValidator ` .
2015-10-30 14:47:11 +03:00
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = DecimalFieldModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-10-30 14:47:11 +03:00
serializer = TestSerializer ( )
assert len ( serializer . fields [ ' decimal_field ' ] . validators ) == 2
2015-12-24 22:00:49 +03:00
def test_min_value_is_passed ( self ) :
"""
Test that the ` MinValueValidator ` is converted to the ` min_value `
argument for the field .
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = DecimalFieldModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-12-24 22:00:49 +03:00
serializer = TestSerializer ( )
assert serializer . fields [ ' decimal_field ' ] . min_value == 1
def test_max_value_is_passed ( self ) :
"""
Test that the ` MaxValueValidator ` is converted to the ` max_value `
argument for the field .
"""
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = DecimalFieldModel
2016-06-02 16:39:10 +03:00
fields = ' __all__ '
2015-12-24 22:00:49 +03:00
serializer = TestSerializer ( )
assert serializer . fields [ ' decimal_field ' ] . max_value == 3
2016-01-06 23:04:51 +03:00
class TestMetaInheritance ( TestCase ) :
def test_extra_kwargs_not_altered ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
non_model_field = serializers . CharField ( )
class Meta :
model = OneFieldModel
read_only_fields = ( ' char_field ' , ' non_model_field ' )
fields = read_only_fields
extra_kwargs = { }
class ChildSerializer ( TestSerializer ) :
class Meta ( TestSerializer . Meta ) :
read_only_fields = ( )
test_expected = dedent ( """
TestSerializer ( ) :
char_field = CharField ( read_only = True )
non_model_field = CharField ( )
""" )
child_expected = dedent ( """
ChildSerializer ( ) :
char_field = CharField ( max_length = 100 )
non_model_field = CharField ( )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( ChildSerializer ( ) ) , child_expected )
self . assertEqual ( repr ( TestSerializer ( ) ) , test_expected )
self . assertEqual ( repr ( ChildSerializer ( ) ) , child_expected )
2016-07-26 18:28:10 +03:00
class OneToOneTargetTestModel ( models . Model ) :
text = models . CharField ( max_length = 100 )
class OneToOneSourceTestModel ( models . Model ) :
2016-10-10 15:03:46 +03:00
target = models . OneToOneField ( OneToOneTargetTestModel , primary_key = True , on_delete = models . CASCADE )
2016-07-26 18:28:10 +03:00
class TestModelFieldValues ( TestCase ) :
def test_model_field ( self ) :
class ExampleSerializer ( serializers . ModelSerializer ) :
class Meta :
model = OneToOneSourceTestModel
fields = ( ' target ' , )
target = OneToOneTargetTestModel ( id = 1 , text = ' abc ' )
source = OneToOneSourceTestModel ( target = target )
serializer = ExampleSerializer ( source )
self . assertEqual ( serializer . data , { ' target ' : 1 } )
2016-08-02 16:33:15 +03:00
class TestUniquenessOverride ( TestCase ) :
def test_required_not_overwritten ( self ) :
class TestModel ( models . Model ) :
field_1 = models . IntegerField ( null = True )
field_2 = models . IntegerField ( )
class Meta :
unique_together = ( ( ' field_1 ' , ' field_2 ' ) , )
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = TestModel
2016-10-10 15:03:46 +03:00
fields = ' __all__ '
2016-08-02 16:33:15 +03:00
extra_kwargs = { ' field_1 ' : { ' required ' : False } }
fields = TestSerializer ( ) . fields
self . assertFalse ( fields [ ' field_1 ' ] . required )
self . assertTrue ( fields [ ' field_2 ' ] . required )
2016-10-13 14:43:43 +03:00
class Issue3674Test ( TestCase ) :
def test_nonPK_foreignkey_model_serializer ( self ) :
class TestParentModel ( models . Model ) :
title = models . CharField ( max_length = 64 )
class TestChildModel ( models . Model ) :
2016-11-29 12:49:18 +03:00
parent = models . ForeignKey ( TestParentModel , related_name = ' children ' , on_delete = models . CASCADE )
2016-10-13 14:43:43 +03:00
value = models . CharField ( primary_key = True , max_length = 64 )
class TestChildModelSerializer ( serializers . ModelSerializer ) :
class Meta :
model = TestChildModel
fields = ( ' value ' , ' parent ' )
class TestParentModelSerializer ( serializers . ModelSerializer ) :
class Meta :
model = TestParentModel
fields = ( ' id ' , ' title ' , ' children ' )
parent_expected = dedent ( """
TestParentModelSerializer ( ) :
id = IntegerField ( label = ' ID ' , read_only = True )
title = CharField ( max_length = 64 )
children = PrimaryKeyRelatedField ( many = True , queryset = TestChildModel . objects . all ( ) )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestParentModelSerializer ( ) ) , parent_expected )
2016-10-13 14:43:43 +03:00
child_expected = dedent ( """
TestChildModelSerializer ( ) :
value = CharField ( max_length = 64 , validators = [ < UniqueValidator ( queryset = TestChildModel . objects . all ( ) ) > ] )
parent = PrimaryKeyRelatedField ( queryset = TestParentModel . objects . all ( ) )
""" )
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestChildModelSerializer ( ) ) , child_expected )
2016-10-13 14:43:43 +03:00
def test_nonID_PK_foreignkey_model_serializer ( self ) :
class TestChildModelSerializer ( serializers . ModelSerializer ) :
class Meta :
model = Issue3674ChildModel
fields = ( ' value ' , ' parent ' )
class TestParentModelSerializer ( serializers . ModelSerializer ) :
class Meta :
model = Issue3674ParentModel
fields = ( ' id ' , ' title ' , ' children ' )
parent = Issue3674ParentModel . objects . create ( title = ' abc ' )
child = Issue3674ChildModel . objects . create ( value = ' def ' , parent = parent )
parent_serializer = TestParentModelSerializer ( parent )
child_serializer = TestChildModelSerializer ( child )
parent_expected = { ' children ' : [ ' def ' ] , ' id ' : 1 , ' title ' : ' abc ' }
self . assertEqual ( parent_serializer . data , parent_expected )
child_expected = { ' parent ' : 1 , ' value ' : ' def ' }
self . assertEqual ( child_serializer . data , child_expected )
2017-02-22 14:06:48 +03:00
class Issue4897TestCase ( TestCase ) :
def test_should_assert_if_writing_readonly_fields ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = OneFieldModel
fields = ( ' char_field ' , )
readonly_fields = fields
obj = OneFieldModel . objects . create ( char_field = ' abc ' )
with pytest . raises ( AssertionError ) as cm :
TestSerializer ( obj ) . fields
cm . match ( r ' readonly_fields ' )
2017-03-28 09:20:55 +03:00
class Test5004UniqueChoiceField ( TestCase ) :
def test_unique_choice_field ( self ) :
class TestUniqueChoiceSerializer ( serializers . ModelSerializer ) :
class Meta :
model = UniqueChoiceModel
fields = ' __all__ '
UniqueChoiceModel . objects . create ( name = ' choice1 ' )
serializer = TestUniqueChoiceSerializer ( data = { ' name ' : ' choice1 ' } )
assert not serializer . is_valid ( )
assert serializer . errors == { ' name ' : [ ' unique choice model with this name already exists. ' ] }
2017-09-04 17:41:04 +03:00
2017-09-04 18:17:43 +03:00
2017-09-04 17:41:04 +03:00
class TestFieldSource ( TestCase ) :
2018-03-21 00:02:22 +03:00
def test_traverse_nullable_fk ( self ) :
"""
A dotted source with nullable elements uses default when any item in the chain is None . #5849.
Similar to model example from test_serializer . py ` test_default_for_multiple_dotted_source ` method ,
but using RelatedField , rather than CharField .
"""
class TestSerializer ( serializers . ModelSerializer ) :
target = serializers . PrimaryKeyRelatedField (
source = ' target.target ' , read_only = True , allow_null = True , default = None
)
class Meta :
model = NestedForeignKeySource
fields = ( ' target ' , )
model = NestedForeignKeySource . objects . create ( )
assert TestSerializer ( model ) . data [ ' target ' ] is None
2017-09-04 17:41:04 +03:00
def test_named_field_source ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
2017-09-04 18:17:43 +03:00
model = RegularFieldsModel
2017-09-04 17:41:04 +03:00
fields = ( ' number_field ' , )
extra_kwargs = {
' number_field ' : {
' source ' : ' integer_field '
}
}
expected = dedent ( """
TestSerializer ( ) :
number_field = IntegerField ( source = ' integer_field ' )
""" )
self . maxDiff = None
2019-04-30 18:53:44 +03:00
self . assertEqual ( repr ( TestSerializer ( ) ) , expected )
2018-08-06 15:30:43 +03:00
2018-08-06 21:11:55 +03:00
class Issue6110TestModel ( models . Model ) :
""" Model without .objects manager. """
2018-08-06 15:30:43 +03:00
2018-08-06 21:11:55 +03:00
name = models . CharField ( max_length = 64 )
all_objects = models . Manager ( )
class Issue6110ModelSerializer ( serializers . ModelSerializer ) :
class Meta :
model = Issue6110TestModel
fields = ( ' name ' , )
2018-08-06 15:30:43 +03:00
2018-08-06 21:11:55 +03:00
class Issue6110Test ( TestCase ) :
def test_model_serializer_custom_manager ( self ) :
instance = Issue6110ModelSerializer ( ) . create ( { ' name ' : ' test_name ' } )
2018-08-06 15:30:43 +03:00
self . assertEqual ( instance . name , ' test_name ' )
2018-08-06 21:11:55 +03:00
def test_model_serializer_custom_manager_error_message ( self ) :
msginitial = ( ' Got a `TypeError` when calling `Issue6110TestModel.all_objects.create()`. ' )
with self . assertRaisesMessage ( TypeError , msginitial ) :
Issue6110ModelSerializer ( ) . create ( { ' wrong_param ' : ' wrong_param ' } )
2019-06-22 11:14:15 +03:00
class Issue6751Model ( models . Model ) :
many_to_many = models . ManyToManyField ( ManyToManyTargetModel , related_name = ' + ' )
char_field = models . CharField ( max_length = 100 )
char_field2 = models . CharField ( max_length = 100 )
@receiver ( m2m_changed , sender = Issue6751Model . many_to_many . through )
def process_issue6751model_m2m_changed ( action , instance , * * _ ) :
if action == ' post_add ' :
instance . char_field = ' value changed by signal '
instance . save ( )
class Issue6751Test ( TestCase ) :
def test_model_serializer_save_m2m_after_instance ( self ) :
class TestSerializer ( serializers . ModelSerializer ) :
class Meta :
model = Issue6751Model
fields = (
' many_to_many ' ,
' char_field ' ,
)
instance = Issue6751Model . objects . create ( char_field = ' initial value ' )
m2m_target = ManyToManyTargetModel . objects . create ( name = ' target ' )
serializer = TestSerializer (
instance = instance ,
data = {
' many_to_many ' : ( m2m_target . id , ) ,
' char_field ' : ' will be changed by signal ' ,
}
)
serializer . is_valid ( )
serializer . save ( )
self . assertEqual ( instance . char_field , ' value changed by signal ' )