diff options
| author | Tom Christie | 2014-09-18 12:17:21 +0100 |
|---|---|---|
| committer | Tom Christie | 2014-09-18 12:17:21 +0100 |
| commit | 87734be5f41de921ac32ad1f6664db243aab6d07 (patch) | |
| tree | 7c6b8d18dc0d505525154c69d112925a95174b5d /tests/test_model_serializer.py | |
| parent | 5b7e4af0d657a575cb15eea85a63a7100c636085 (diff) | |
| download | django-rest-framework-87734be5f41de921ac32ad1f6664db243aab6d07.tar.bz2 | |
Configuration correctness tests on ModelSerializer
Diffstat (limited to 'tests/test_model_serializer.py')
| -rw-r--r-- | tests/test_model_serializer.py | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py new file mode 100644 index 00000000..63e36452 --- /dev/null +++ b/tests/test_model_serializer.py @@ -0,0 +1,322 @@ +""" +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. +""" +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +def dedent(blocktext): + return '\n'.join([line[12:] for line in blocktext.splitlines()[1:-1]]) + + +# Testing regular field mappings + +class RegularFieldsModel(models.Model): + 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_seperated_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) + + def method(self): + return 'method' + + +class TestRegularFieldMappings(TestCase): + def test_regular_fields(self): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = RegularFieldsModel + + expected = dedent(""" + TestSerializer(): + auto_field = IntegerField(read_only=True) + big_integer_field = IntegerField() + boolean_field = BooleanField(default=False) + char_field = CharField(max_length=100) + comma_seperated_integer_field = CharField(max_length=100, validators=[<django.core.validators.RegexValidator object>]) + 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() + null_boolean_field = BooleanField(required=False) + positive_integer_field = IntegerField() + positive_small_integer_field = IntegerField() + slug_field = SlugField(max_length=100) + small_integer_field = IntegerField() + text_field = CharField() + time_field = TimeField() + url_field = URLField(max_length=100) + """) + + self.assertEqual(repr(TestSerializer()), expected) + + 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 + fields = ('pk', 'char_field') + extra_kwargs = {'char_field': {'default': 'extra'}} + + expected = dedent(""" + TestSerializer(): + pk = IntegerField(label='Auto field', read_only=True) + char_field = CharField(default='extra', max_length=100) + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_invalid_field(self): + """ + Field names that do not map to a model field or relationship should + raise a configuration errror. + """ + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = RegularFieldsModel + fields = ('auto_field', 'invalid') + + with self.assertRaises(ImproperlyConfigured) as excinfo: + TestSerializer() + expected = 'Field name `invalid` is not valid for model `ModelBase`.' + assert str(excinfo.exception) == expected + + def test_missing_field(self): + class TestSerializer(serializers.ModelSerializer): + missing = serializers.ReadOnlyField() + + class Meta: + model = RegularFieldsModel + fields = ('auto_field',) + + with self.assertRaises(ImproperlyConfigured) as excinfo: + TestSerializer() + expected = ( + 'Field `missing` has been declared on serializer ' + '`TestSerializer`, but is missing from `Meta.fields`.' + ) + assert str(excinfo.exception) == expected + + +# Testing relational field mappings + +class ForeignKeyTargetModel(models.Model): + name = models.CharField(max_length=100) + + +class ManyToManyTargetModel(models.Model): + name = models.CharField(max_length=100) + + +class OneToOneTargetModel(models.Model): + name = models.CharField(max_length=100) + + +class ThroughTargetModel(models.Model): + name = models.CharField(max_length=100) + + +class Supplementary(models.Model): + extra = models.IntegerField() + forwards = models.ForeignKey('ThroughTargetModel') + backwards = models.ForeignKey('RelationalModel') + + +class RelationalModel(models.Model): + foreign_key = models.ForeignKey(ForeignKeyTargetModel, related_name='reverse_foreign_key') + many_to_many = models.ManyToManyField(ManyToManyTargetModel, related_name='reverse_many_to_many') + one_to_one = models.OneToOneField(OneToOneTargetModel, related_name='reverse_one_to_one') + through = models.ManyToManyField(ThroughTargetModel, through=Supplementary, related_name='reverse_through') + + +class TestRelationalFieldMappings(TestCase): + def test_flat_relational_fields(self): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = RelationalModel + + expected = dedent(""" + TestSerializer(): + id = IntegerField(label='ID', read_only=True) + foreign_key = PrimaryKeyRelatedField(queryset=ForeignKeyTargetModel.objects.all()) + one_to_one = PrimaryKeyRelatedField(queryset=OneToOneTargetModel.objects.all()) + many_to_many = PrimaryKeyRelatedField(many=True, queryset=ManyToManyTargetModel.objects.all()) + through = PrimaryKeyRelatedField(many=True, read_only=True) + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_nested_relational_fields(self): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = RelationalModel + depth = 1 + + expected = dedent(""" + TestSerializer(): + id = IntegerField(label='ID', read_only=True) + foreign_key = NestedSerializer(read_only=True): + id = IntegerField(label='ID', read_only=True) + name = CharField(max_length=100) + one_to_one = NestedSerializer(read_only=True): + id = IntegerField(label='ID', read_only=True) + name = CharField(max_length=100) + many_to_many = NestedSerializer(many=True, read_only=True): + id = IntegerField(label='ID', read_only=True) + name = CharField(max_length=100) + through = NestedSerializer(many=True, read_only=True): + id = IntegerField(label='ID', read_only=True) + name = CharField(max_length=100) + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_flat_hyperlinked_fields(self): + class TestSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = RelationalModel + + expected = dedent(""" + TestSerializer(): + url = HyperlinkedIdentityField(view_name='relationalmodel-detail') + foreign_key = HyperlinkedRelatedField(queryset=ForeignKeyTargetModel.objects.all(), view_name='foreignkeytargetmodel-detail') + one_to_one = HyperlinkedRelatedField(queryset=OneToOneTargetModel.objects.all(), view_name='onetoonetargetmodel-detail') + many_to_many = HyperlinkedRelatedField(many=True, queryset=ManyToManyTargetModel.objects.all(), view_name='manytomanytargetmodel-detail') + through = HyperlinkedRelatedField(many=True, read_only=True, view_name='throughtargetmodel-detail') + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_nested_hyperlinked_fields(self): + class TestSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = RelationalModel + depth = 1 + + expected = dedent(""" + TestSerializer(): + url = HyperlinkedIdentityField(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.assertEqual(repr(TestSerializer()), expected) + + def test_flat_reverse_foreign_key(self): + 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()) + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_flat_reverse_one_to_one(self): + 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()) + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_flat_reverse_many_to_many(self): + 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()) + """) + self.assertEqual(repr(TestSerializer()), expected) + + def test_flat_reverse_through(self): + 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) + """) + self.assertEqual(repr(TestSerializer()), expected) |
