From 7502b2d296bfeebe1290f6c3967dd98d97a07d58 Mon Sep 17 00:00:00 2001 From: Oliver Sauder Date: Sun, 3 Oct 2021 22:56:40 +0400 Subject: [PATCH] Check for reserved field names in serializer meta class Fixes #518 Fixes #710 This is to avoid an incomprehensible exception during runtime when either meta or results is used as a field name. --- CHANGELOG.md | 3 ++- rest_framework_json_api/serializers.py | 19 +++++++++++++++++++ tests/test_serializers.py | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3011d2e..f25edb39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,9 @@ any parts of the framework not mentioned in the documentation should generally b ### Fixed -* Adjusted error messages to correctly use capitial "JSON:API" abbreviation as used in the specification. +* Adjusted error messages to correctly use capital "JSON:API" abbreviation as used in the specification. * Avoid error when `parser_context` is `None` while parsing. +* Raise comprehensible error when reserved field names `meta` and `results` are used. ### Changed diff --git a/rest_framework_json_api/serializers.py b/rest_framework_json_api/serializers.py index ce80874a..ee6d15b6 100644 --- a/rest_framework_json_api/serializers.py +++ b/rest_framework_json_api/serializers.py @@ -184,6 +184,25 @@ def __repr__(self): class SerializerMetaclass(SerializerMetaclass): + + _reserved_field_names = {"meta", "results"} + + @classmethod + def _get_declared_fields(cls, bases, attrs): + fields = super()._get_declared_fields(bases, attrs) + + found_reserved_field_names = cls._reserved_field_names.intersection( + fields.keys() + ) + if found_reserved_field_names: + raise AttributeError( + f"Serializer class {attrs['__module__']}.{attrs['__qualname__']} uses " + f"following reserved field name(s) which is not allowed: " + f"{', '.join(sorted(found_reserved_field_names))}" + ) + + return fields + def __new__(cls, name, bases, attrs): serializer = super().__new__(cls, name, bases, attrs) diff --git a/tests/test_serializers.py b/tests/test_serializers.py index 6726fa8c..505111ca 100644 --- a/tests/test_serializers.py +++ b/tests/test_serializers.py @@ -1,3 +1,4 @@ +import pytest from django.db import models from rest_framework_json_api import serializers @@ -33,3 +34,17 @@ class Meta: } assert included_serializers == expected_included_serializers + + +def test_reserved_field_names(): + with pytest.raises(AttributeError) as e: + + class ReservedFieldNamesSerializer(serializers.Serializer): + meta = serializers.CharField() + results = serializers.CharField() + + assert str(e.value) == ( + "Serializer class tests.test_serializers.test_reserved_field_names.." + "ReservedFieldNamesSerializer uses following reserved field name(s) which is " + "not allowed: meta, results" + )