Skip to content

Commit 177bfbc

Browse files
author
Boris Pleshakov
committed
f move DeprecationWarning from settings to metaclass, which ensures that DeprecationWarning raises whenever nested serializer is used without correct settings
1 parent 67442ab commit 177bfbc

File tree

4 files changed

+54
-16
lines changed

4 files changed

+54
-16
lines changed

example/tests/test_nested_errors.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ def post(self, request, *args, **kwargs):
5757

5858

5959
@override_settings(ROOT_URLCONF=__name__)
60-
@pytest.mark.filterwarnings('ignore:Rendering nested')
6160
class TestNestedErrors(TestBase):
6261

6362
def setUp(self):
@@ -200,3 +199,18 @@ def test_third_level_dict_error(self):
200199
}
201200

202201
self.perform_error_test(data, '/data/attributes/comments/0/attachment/data')
202+
203+
204+
@pytest.mark.filterwarning('default::DeprecationWarning:rest_framework_json_api.serializers')
205+
def test_deprecation_warning(recwarn):
206+
class DummyNestedSerializer(serializers.Serializer):
207+
field = serializers.CharField()
208+
209+
class DummySerializer(serializers.Serializer):
210+
nested = DummyNestedSerializer(many=True)
211+
212+
assert len(recwarn) == 1
213+
warning = recwarn.pop(DeprecationWarning)
214+
assert warning
215+
assert str(warning.message).startswith('Rendering')
216+

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ DJANGO_SETTINGS_MODULE=example.settings.test
33
filterwarnings =
44
error::DeprecationWarning
55
error::PendingDeprecationWarning
6+
ignore::DeprecationWarning:rest_framework_json_api.serializers

rest_framework_json_api/serializers.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import warnings
2+
13
import inflection
24
from django.core.exceptions import ObjectDoesNotExist
35
from django.db.models.query import QuerySet
@@ -117,8 +119,41 @@ def validate_path(serializer_class, field_path, path):
117119
super(IncludedResourcesValidationMixin, self).__init__(*args, **kwargs)
118120

119121

122+
class SerializerMetaclass(SerializerMetaclass):
123+
124+
@classmethod
125+
def _get_declared_fields(cls, bases, attrs):
126+
fields = super()._get_declared_fields(bases, attrs)
127+
setting_name = 'JSON_API_SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE'
128+
for field_name, field in fields.items():
129+
if isinstance(field, BaseSerializer) and \
130+
not json_api_settings.SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE and \
131+
not hasattr(json_api_settings.user_settings, setting_name):
132+
clazz = '{}.{}'.format(attrs['__module__'], attrs['__qualname__'])
133+
if isinstance(field, ListSerializer):
134+
nested_class = type(field.child).__name__
135+
else:
136+
nested_class = type(field).__name__
137+
138+
warnings.warn(DeprecationWarning(
139+
"Rendering nested serializers in relations by default is deprecated and will "
140+
"be changed in future releases. Please, use ResourceRelatedField instead of "
141+
"{} in serializer {} or set JSON_API_SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE"
142+
" to False".format(nested_class, clazz)))
143+
return fields
144+
145+
146+
# If user imports serializer from here we can catch class definition and check
147+
# nested serializers for depricated use. Probably it is not bad idea to add
148+
# sparse and included mixins to this definition, in case people want to use
149+
# DRF-JA without models underlying.
150+
class Serializer(Serializer, metaclass=SerializerMetaclass):
151+
pass
152+
153+
120154
class HyperlinkedModelSerializer(
121-
IncludedResourcesValidationMixin, SparseFieldsetsMixin, HyperlinkedModelSerializer
155+
IncludedResourcesValidationMixin, SparseFieldsetsMixin, HyperlinkedModelSerializer,
156+
metaclass=SerializerMetaclass
122157
):
123158
"""
124159
A type of `ModelSerializer` that uses hyperlinked relationships instead
@@ -134,7 +169,8 @@ class HyperlinkedModelSerializer(
134169
"""
135170

136171

137-
class ModelSerializer(IncludedResourcesValidationMixin, SparseFieldsetsMixin, ModelSerializer):
172+
class ModelSerializer(IncludedResourcesValidationMixin, SparseFieldsetsMixin, ModelSerializer,
173+
metaclass=SerializerMetaclass):
138174
"""
139175
A `ModelSerializer` is just a regular `Serializer`, except that:
140176

rest_framework_json_api/settings.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,6 @@ def __init__(self, user_settings=settings, defaults=DEFAULTS):
2929
self.defaults = defaults
3030
self.user_settings = user_settings
3131

32-
field_name = JSON_API_SETTINGS_PREFIX + 'SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE'
33-
34-
value = getattr(
35-
self.user_settings,
36-
field_name,
37-
self.defaults['SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE'])
38-
39-
if not value and not hasattr(self.user_settings, field_name):
40-
warnings.warn(DeprecationWarning(
41-
"Rendering nested serializers in relations by default is deprecated and will be "
42-
"changed in future releases. Please, use ResourceRelatedField or set "
43-
"JSON_API_SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE to False"))
44-
4532
def __getattr__(self, attr):
4633
if attr not in self.defaults:
4734
raise AttributeError("Invalid JSON API setting: '%s'" % attr)

0 commit comments

Comments
 (0)