Skip to content

Commit e6545c8

Browse files
committed
Verified in all fields whether reserved field names are used
In meta class only specifically declared fields in serializer are accessible. In case of `ModelSerializer` fields may be just on the model or if a user has overwritten what fields are being returned during runtime DJA won't notice. So there does not seem to be another way then simply hooking into the `get_fields` method to check for reserved field names.
1 parent 0816192 commit e6545c8

File tree

2 files changed

+26
-19
lines changed

2 files changed

+26
-19
lines changed

rest_framework_json_api/serializers.py

+24-19
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,27 @@ def validate_path(serializer_class, field_path, path):
153153
super().__init__(*args, **kwargs)
154154

155155

156+
class ReservedFieldNamesMixin:
157+
"""Ensures that reserved field names are not used and an error raised instead."""
158+
159+
_reserved_field_names = {"meta", "results"}
160+
161+
def get_fields(self):
162+
fields = super().get_fields()
163+
164+
found_reserved_field_names = self._reserved_field_names.intersection(
165+
fields.keys()
166+
)
167+
if found_reserved_field_names:
168+
raise AttributeError(
169+
f"Serializer class {self.__class__.__module__}.{self.__class__.__qualname__} "
170+
f"uses following reserved field name(s) which is not allowed: "
171+
f"{', '.join(sorted(found_reserved_field_names))}"
172+
)
173+
174+
return fields
175+
176+
156177
class LazySerializersDict(Mapping):
157178
"""
158179
A dictionary of serializers which lazily import dotted class path and self.
@@ -184,25 +205,6 @@ def __repr__(self):
184205

185206

186207
class SerializerMetaclass(SerializerMetaclass):
187-
188-
_reserved_field_names = {"meta", "results"}
189-
190-
@classmethod
191-
def _get_declared_fields(cls, bases, attrs):
192-
fields = super()._get_declared_fields(bases, attrs)
193-
194-
found_reserved_field_names = cls._reserved_field_names.intersection(
195-
fields.keys()
196-
)
197-
if found_reserved_field_names:
198-
raise AttributeError(
199-
f"Serializer class {attrs['__module__']}.{attrs['__qualname__']} uses "
200-
f"following reserved field name(s) which is not allowed: "
201-
f"{', '.join(sorted(found_reserved_field_names))}"
202-
)
203-
204-
return fields
205-
206208
def __new__(cls, name, bases, attrs):
207209
serializer = super().__new__(cls, name, bases, attrs)
208210

@@ -228,6 +230,7 @@ def __new__(cls, name, bases, attrs):
228230
class Serializer(
229231
IncludedResourcesValidationMixin,
230232
SparseFieldsetsMixin,
233+
ReservedFieldNamesMixin,
231234
Serializer,
232235
metaclass=SerializerMetaclass,
233236
):
@@ -251,6 +254,7 @@ class Serializer(
251254
class HyperlinkedModelSerializer(
252255
IncludedResourcesValidationMixin,
253256
SparseFieldsetsMixin,
257+
ReservedFieldNamesMixin,
254258
HyperlinkedModelSerializer,
255259
metaclass=SerializerMetaclass,
256260
):
@@ -271,6 +275,7 @@ class HyperlinkedModelSerializer(
271275
class ModelSerializer(
272276
IncludedResourcesValidationMixin,
273277
SparseFieldsetsMixin,
278+
ReservedFieldNamesMixin,
274279
ModelSerializer,
275280
metaclass=SerializerMetaclass,
276281
):

tests/test_serializers.py

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class ReservedFieldNamesSerializer(serializers.Serializer):
4343
meta = serializers.CharField()
4444
results = serializers.CharField()
4545

46+
ReservedFieldNamesSerializer().fields
47+
4648
assert str(e.value) == (
4749
"Serializer class tests.test_serializers.test_reserved_field_names.<locals>."
4850
"ReservedFieldNamesSerializer uses following reserved field name(s) which is "

0 commit comments

Comments
 (0)