From 00da2414827987e9934ebe7bf2f9a3afea1cdb13 Mon Sep 17 00:00:00 2001 From: Jeff Fein-Worton Date: Fri, 12 Dec 2014 22:14:22 -0800 Subject: [PATCH 1/5] documentation typo base-name -> base_name --- docs/api-guide/routers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 080230faf..929a1710c 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -41,7 +41,7 @@ The example above would generate the following URL patterns: **Note**: The `base_name` argument is used to specify the initial part of the view name pattern. In the example above, that's the `user` or `account` part. -Typically you won't *need* to specify the `base-name` argument, but if you have a viewset where you've defined a custom `get_queryset` method, then the viewset may not have a `.queryset` attribute set. If you try to register that viewset you'll see an error like this: +Typically you won't *need* to specify the `base_name` argument, but if you have a viewset where you've defined a custom `get_queryset` method, then the viewset may not have a `.queryset` attribute set. If you try to register that viewset you'll see an error like this: 'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute. From c0b9115beca00fda36a50532fbe62e3b39b4e972 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 13 Dec 2014 14:17:24 +0000 Subject: [PATCH 2/5] Improve check for nested writes --- rest_framework/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 9226895e0..5adbca3bd 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -611,6 +611,7 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data): # profile = ProfileSerializer() assert not any( isinstance(field, BaseSerializer) and (key in validated_data) + and isinstance(validated_data[key], (list, dict)) for key, field in serializer.fields.items() ), ( 'The `.{method_name}()` method does not support writable nested' @@ -630,6 +631,7 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data): # address = serializer.CharField('profile.address') assert not any( '.' in field.source and (key in validated_data) + and isinstance(validated_data[key], (list, dict)) for key, field in serializer.fields.items() ), ( 'The `.{method_name}()` method does not support writable dotted-source ' From aa571abb2089aedb5902a8f1670e59b4df99f3e9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 13 Dec 2014 14:58:04 +0000 Subject: [PATCH 3/5] Better errors when serializer has incorrectly named field. --- rest_framework/fields.py | 18 +++++++++++++++++- tests/test_serializer.py | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 25122e141..205efd2f8 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -274,7 +274,23 @@ class Field(object): Given the *outgoing* object instance, return the primitive value that should be used for this field. """ - return get_attribute(instance, self.source_attrs) + try: + return get_attribute(instance, self.source_attrs) + except (KeyError, AttributeError) as exc: + msg = ( + 'Got {exc_type} when attempting to get a value for field ' + '`{field}` on serializer `{serializer}`.\nThe serializer ' + 'field might be named incorrectly and not match ' + 'any attribute or key on the `{instance}` instance.\n' + 'Original exception text was: {exc}.'.format( + exc_type=type(exc).__name__, + field=self.field_name, + serializer=self.parent.__class__.__name__, + instance=instance.__class__.__name__, + exc=exc + ) + ) + raise type(exc)(msg) def get_default(self): """ diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 6dabaf42e..9d47b0aaa 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from rest_framework import serializers import pytest @@ -175,3 +176,23 @@ class TestStarredSource: instance = {'a': 1, 'b': 2, 'c': 3, 'd': 4} serializer = self.Serializer(instance) assert serializer.data == self.data + + +class TestIncorrectlyConfigured: + def test_incorrect_field_name(self): + class ExampleSerializer(serializers.Serializer): + incorrect_name = serializers.IntegerField() + + class ExampleObject: + def __init__(self): + self.correct_name = 123 + + instance = ExampleObject() + serializer = ExampleSerializer(instance) + with pytest.raises(AttributeError) as exc_info: + serializer.data + assert str(exc_info.value) == ( + "Got AttributeError when attempting to get a value for field `incorrect_name` on serializer `ExampleSerializer`.\n" + "The serializer field might be named incorrectly and not match any attribute or key on the `ExampleObject` instance.\n" + "Original exception text was: ExampleObject instance has no attribute 'incorrect_name'." + ) From 4fb757146af8e805e30cfe4a8914c9fb7251b3fc Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 13 Dec 2014 15:04:39 +0000 Subject: [PATCH 4/5] Fix test for python2/3 compat --- tests/test_serializer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 9d47b0aaa..56b390956 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -191,8 +191,9 @@ class TestIncorrectlyConfigured: serializer = ExampleSerializer(instance) with pytest.raises(AttributeError) as exc_info: serializer.data - assert str(exc_info.value) == ( + msg = str(exc_info.value) + assert msg.startswith( "Got AttributeError when attempting to get a value for field `incorrect_name` on serializer `ExampleSerializer`.\n" "The serializer field might be named incorrectly and not match any attribute or key on the `ExampleObject` instance.\n" - "Original exception text was: ExampleObject instance has no attribute 'incorrect_name'." + "Original exception text was:" ) From 2d470eef809b119c8c72009c81d652ddbf895e0b Mon Sep 17 00:00:00 2001 From: Brian Jacobel Date: Sat, 13 Dec 2014 14:47:11 -0500 Subject: [PATCH 5/5] Change serializers.Field to serializers.ReadOnlyField for 3.x compatibility Using this code snippet as-is on DRF 3.0.1 results in a NotImplementedError being raised for to_representation due to 3.0's changed behavior with serializers.Field. The code snippet should be updated to use serializers.ReadOnlyField instead. Further discussion here: https://groups.google.com/forum/?fromgroups=#!topic/django-rest-framework/aX8mLT_v3yc --- docs/api-guide/pagination.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index 9b7086c54..834292920 100644 --- a/docs/api-guide/pagination.md +++ b/docs/api-guide/pagination.md @@ -128,7 +128,7 @@ For example, to nest a pair of links labelled 'prev' and 'next', and set the nam class CustomPaginationSerializer(pagination.BasePaginationSerializer): links = LinksSerializer(source='*') # Takes the page object as the source - total_results = serializers.Field(source='paginator.count') + total_results = serializers.ReadOnlyField(source='paginator.count') results_field = 'objects'