Configuration correctness tests on ModelSerializer

This commit is contained in:
Tom Christie 2014-09-18 12:17:21 +01:00
parent 5b7e4af0d6
commit 87734be5f4
2 changed files with 112 additions and 3 deletions

View File

@ -10,7 +10,7 @@ python primitives.
2. The process of marshalling between python primitives and request and
response content is handled by parsers and renderers.
"""
from django.core.exceptions import ValidationError
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
from django.utils import six
from django.utils.datastructures import SortedDict
@ -358,6 +358,7 @@ class ModelSerializer(Serializer):
model = getattr(self.Meta, 'model')
fields = getattr(self.Meta, 'fields', None)
depth = getattr(self.Meta, 'depth', 0)
extra_kwargs = getattr(self.Meta, 'extra_kwargs', {})
# Retrieve metadata about fields & relationships on the model class.
info = model_meta.get_field_info(model)
@ -405,9 +406,32 @@ class ModelSerializer(Serializer):
if not issubclass(field_cls, HyperlinkedRelatedField):
kwargs.pop('view_name', None)
else:
assert False, 'Field name `%s` is not valid.' % field_name
elif hasattr(model, field_name):
# Create a read only field for model methods and properties.
field_cls = ReadOnlyField
kwargs = {}
else:
raise ImproperlyConfigured(
'Field name `%s` is not valid for model `%s`.' %
(field_name, model.__class__.__name__)
)
# Check that any fields declared on the class are
# also explicity included in `Meta.fields`.
missing_fields = set(declared_fields.keys()) - set(fields)
if missing_fields:
missing_field = list(missing_fields)[0]
raise ImproperlyConfigured(
'Field `%s` has been declared on serializer `%s`, but '
'is missing from `Meta.fields`.' %
(missing_field, self.__class__.__name__)
)
# Populate any kwargs defined in `Meta.extra_kwargs`
kwargs.update(extra_kwargs.get(field_name, {}))
# Create the serializer field.
ret[field_name] = field_cls(**kwargs)
return ret

View File

@ -5,6 +5,7 @@ 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
@ -37,6 +38,9 @@ class RegularFieldsModel(models.Model):
time_field = models.TimeField()
url_field = models.URLField(max_length=100)
def method(self):
return 'method'
class TestRegularFieldMappings(TestCase):
def test_regular_fields(self):
@ -69,6 +73,87 @@ class TestRegularFieldMappings(TestCase):
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