mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Merge branch 'version-3.1' into cursor-pagination
This commit is contained in:
commit
5e52f0fd8c
|
@ -60,7 +60,7 @@ For example, you can append `router.urls` to a list of existing views…
|
|||
router.register(r'accounts', AccountViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^forgot-password/$, ForgotPasswordFormView.as_view(),
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view(),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
@ -68,14 +68,14 @@ For example, you can append `router.urls` to a list of existing views…
|
|||
Alternatively you can use Django's `include` function, like so…
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^forgot-password/$, ForgotPasswordFormView.as_view(),
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view(),
|
||||
url(r'^', include(router.urls))
|
||||
]
|
||||
|
||||
Router URL patterns can also be namespaces.
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^forgot-password/$, ForgotPasswordFormView.as_view(),
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view(),
|
||||
url(r'^api/', include(router.urls, namespace='api'))
|
||||
]
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ Open the file `snippets/serializers.py` again, and replace the `SnippetSerialize
|
|||
model = Snippet
|
||||
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
|
||||
|
||||
One nice property that serializers have is that you can inspect all the fields in a serializer instance, by printing it's representation. Open the Django shell with `python manage.py shell`, then try the following:
|
||||
One nice property that serializers have is that you can inspect all the fields in a serializer instance, by printing its representation. Open the Django shell with `python manage.py shell`, then try the following:
|
||||
|
||||
>>> from snippets.serializers import SnippetSerializer
|
||||
>>> serializer = SnippetSerializer()
|
||||
|
|
|
@ -18,7 +18,7 @@ def unicode_repr(instance):
|
|||
# Get the repr of an instance, but ensure it is a unicode string
|
||||
# on both python 3 (already the case) and 2 (not the case).
|
||||
if six.PY2:
|
||||
repr(instance).decode('utf-8')
|
||||
return repr(instance).decode('utf-8')
|
||||
return repr(instance)
|
||||
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ class SerializerMetaclass(type):
|
|||
# If this class is subclassing another Serializer, add that Serializer's
|
||||
# fields. Note that we loop over the bases in *reverse*. This is necessary
|
||||
# in order to maintain the correct order of fields.
|
||||
for base in bases[::-1]:
|
||||
for base in reversed(bases):
|
||||
if hasattr(base, '_declared_fields'):
|
||||
fields = list(base._declared_fields.items()) + fields
|
||||
|
||||
|
@ -899,7 +899,15 @@ class ModelSerializer(Serializer):
|
|||
if fields is not None:
|
||||
# Ensure that all declared fields have also been included in the
|
||||
# `Meta.fields` option.
|
||||
for field_name in declared_fields:
|
||||
|
||||
# Do not require any fields that are declared a parent class,
|
||||
# in order to allow serializer subclasses to only include
|
||||
# a subset of fields.
|
||||
required_field_names = set(declared_fields)
|
||||
for cls in self.__class__.__bases__:
|
||||
required_field_names -= set(getattr(cls, '_declared_fields', []))
|
||||
|
||||
for field_name in required_field_names:
|
||||
assert field_name in fields, (
|
||||
"The field '{field_name}' was declared on serializer "
|
||||
"{serializer_class}, but has not been included in the "
|
||||
|
|
|
@ -105,3 +105,6 @@ class BindingDict(collections.MutableMapping):
|
|||
|
||||
def __len__(self):
|
||||
return len(self.fields)
|
||||
|
||||
def __repr__(self):
|
||||
return dict.__repr__(self.fields)
|
||||
|
|
|
@ -5,11 +5,14 @@ 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 __future__ import unicode_literals
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator, MinLengthValidator
|
||||
from django.db import models
|
||||
from django.test import TestCase
|
||||
from django.utils import six
|
||||
from rest_framework import serializers
|
||||
from rest_framework.compat import unicode_repr
|
||||
|
||||
|
||||
def dedent(blocktext):
|
||||
|
@ -124,7 +127,7 @@ class TestRegularFieldMappings(TestCase):
|
|||
url_field = URLField(max_length=100)
|
||||
custom_field = ModelField(model_field=<tests.test_model_serializer.CustomField: custom_field>)
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_field_options(self):
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
|
@ -142,7 +145,14 @@ class TestRegularFieldMappings(TestCase):
|
|||
descriptive_field = IntegerField(help_text='Some help text', label='A label')
|
||||
choices_field = ChoiceField(choices=[('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')])
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
if six.PY2:
|
||||
# This particular case is too awkward to resolve fully across
|
||||
# both py2 and py3.
|
||||
expected = expected.replace(
|
||||
"('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')",
|
||||
"(u'red', u'Red'), (u'blue', u'Blue'), (u'green', u'Green')"
|
||||
)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_method_field(self):
|
||||
"""
|
||||
|
@ -229,6 +239,26 @@ class TestRegularFieldMappings(TestCase):
|
|||
)
|
||||
assert str(excinfo.exception) == expected
|
||||
|
||||
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 Meta:
|
||||
model = RegularFieldsModel
|
||||
|
||||
class ChildSerializer(TestSerializer):
|
||||
missing = serializers.ReadOnlyField()
|
||||
|
||||
class Meta:
|
||||
model = RegularFieldsModel
|
||||
fields = ('auto_field',)
|
||||
|
||||
ChildSerializer().fields
|
||||
|
||||
|
||||
# Tests for relational field mappings.
|
||||
# ------------------------------------
|
||||
|
@ -276,7 +306,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
many_to_many = PrimaryKeyRelatedField(many=True, queryset=ManyToManyTargetModel.objects.all())
|
||||
through = PrimaryKeyRelatedField(many=True, read_only=True)
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_nested_relations(self):
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
|
@ -300,7 +330,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
id = IntegerField(label='ID', read_only=True)
|
||||
name = CharField(max_length=100)
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_hyperlinked_relations(self):
|
||||
class TestSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
@ -315,7 +345,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
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)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_nested_hyperlinked_relations(self):
|
||||
class TestSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
@ -339,7 +369,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
url = HyperlinkedIdentityField(view_name='throughtargetmodel-detail')
|
||||
name = CharField(max_length=100)
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_pk_reverse_foreign_key(self):
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
|
@ -353,7 +383,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
name = CharField(max_length=100)
|
||||
reverse_foreign_key = PrimaryKeyRelatedField(many=True, queryset=RelationalModel.objects.all())
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_pk_reverse_one_to_one(self):
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
|
@ -367,7 +397,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
name = CharField(max_length=100)
|
||||
reverse_one_to_one = PrimaryKeyRelatedField(queryset=RelationalModel.objects.all())
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_pk_reverse_many_to_many(self):
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
|
@ -381,7 +411,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
name = CharField(max_length=100)
|
||||
reverse_many_to_many = PrimaryKeyRelatedField(many=True, queryset=RelationalModel.objects.all())
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
def test_pk_reverse_through(self):
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
|
@ -395,7 +425,7 @@ class TestRelationalFieldMappings(TestCase):
|
|||
name = CharField(max_length=100)
|
||||
reverse_through = PrimaryKeyRelatedField(many=True, read_only=True)
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
self.assertEqual(unicode_repr(TestSerializer()), expected)
|
||||
|
||||
|
||||
class TestIntegration(TestCase):
|
||||
|
|
Loading…
Reference in New Issue
Block a user