如何使用Django REST序列化程序对保留键进行验证?

时间:2018-01-25 10:56:50

标签: python django django-rest-framework serializer

这可能是一个简单的问题,有眨眼的解决方法。但我无法完成它。 我现在正在创建webhook端点。并坚持serializer课程 我的班级不能将from用作班级属性

Python 3.6.4
Django的== 1.11.9
djangorest == 3.7.7

@pytest.fixture
def like_object():
    """LIKE object response from Facebook"""
    return {
        "object": "page",
        "entry": [{
            "changes": [{
                "field": "feed",
                "value": {
                    "item": "reaction",
                    "verb": "add",
                    "reaction_type": "like",
                    "created_time": 1516183830,
                    "post_id": "1331351323541869_1844740022202994",
                    "from": {
                        "name": "Elcoie Sieve",
                        "id": "1639217166122728"
                    },
                    "parent_id": "1331351323541869_1844740022202994"
                }
            }],
            "time": 1516183830, "id": "1331351323541869"
        }]
    }

serializers.py

class FacebookReactionSerializer(serializers.Serializer):
    """
    value serializer the inner most of the payload
    """
    item = serializers.CharField()
    verb = serializers.CharField()
    reaction_type = serializers.CharField()
    created_time = serializers.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(4086831600)]
    )  # Limit the maximum epoch to 2099 July 4th 7:00AM
    post_id = serializers.CharField(max_length=40)
    from = FromSerializer()
    parent_id = serializers.CharField()

    def validate(self, attrs):
        """
        `from` is a python reserved word the add _ to distinguish it from them
        :param attrs:
        :return:
        """
        from_ = attrs.get('from')
        pass

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

尝试:

ffrom = FromSerializer(source='from')

不起作用

ATTEMPT2:

class FacebookReactionSerializer(serializers.Serializer):
    """
    value serializer the inner most of the payload
    """
    item = serializers.CharField()
    verb = serializers.CharField()
    reaction_type = serializers.CharField()
    created_time = serializers.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(4086831600)]
    )  # Limit the maximum epoch to 2099 July 4th 7:00AM
    post_id = serializers.CharField(max_length=40)
    from_key = FromSerializer()
    parent_id = serializers.CharField()

    def to_representation(self, instance):
        """
        https://stackoverflow.com/questions/47630356/using-the-reserved-word-class-as-field-name-in-django-and-django-rest-framewor
        :param instance:
        :return:
        """
        data = super().to_representation(instance)
        keys = list(data.keys())
        keys.insert(keys.index('from_key'), 'from')
        keys.remove('from_key')
        from_key = data.pop('from_key')
        data.update({'from': from_key})
        response = OrderedDict((k, data[k]) for k in keys)
        return response

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

这里的测试用例失败是断点

(Pdb) serializer
FacebookReactionSerializer(data={'item': 'reaction', 'verb': 'add', 'reaction_type': 'like', 'created_time': 1516183830, 'post_id': '1331351323541869_1844740022202994', 'from': {'name': 'Krittuch Onnom', 'id': '1639217166122728'}, 'parent_id': '1331351323541869_1844740022202994'}):
    item = CharField()
    verb = CharField()
    reaction_type = CharField()
    created_time = IntegerField(validators=[<rest_framework.compat.MinValueValidator object>, <rest_framework.compat.MaxValueValidator object>])
    post_id = CharField(max_length=40)
    from_key = FromSerializer():
        name = CharField()
        id = CharField()
    parent_id = CharField()
(Pdb) serializer.errors
*** AssertionError: You must call `.is_valid()` before accessing `.errors`.
(Pdb) serializer.is_valid()
False
(Pdb) serializer.errors
{'from_key': ['This field is required.']}

Attempt3:
还要添加`._declared_fields ['from_key']

class FacebookReactionSerializer(serializers.Serializer):
    item = serializers.CharField()
    verb = serializers.CharField()
    reaction_type = serializers.CharField()
    created_time = serializers.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(4086831600)]
    )  # Limit the maximum epoch to 2099 July 4th 7:00AM
    post_id = serializers.CharField(max_length=40)
    from_key = FromSerializer()
    parent_id = serializers.CharField()

    def to_representation(self, instance):
        data = super().to_representation(instance)
        keys = list(data.keys())
        keys.insert(keys.index('from_key'), 'from')
        keys.remove('from_key')
        from_key = data.pop('from_key')
        data.update({'from': from_key})
        response = OrderedDict((k, data[k]) for k in keys)
        return response

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

FacebookReactionSerializer._declared_fields["from"] = serializers.CharField(source="from_key")

调试行:

(Pdb) serializer.is_valid()
False
(Pdb) serializer.errors
{'from_key': ['This field is required.'], 'from': ['Not a valid string.']}

我越来越近了,但这还不够

Attempt4.1:

不行。保持相同的错误。 from_key仍然存在。 我是从child序列化器写的。我必须使用FromSerializer而不是CharField

    class FacebookReactionSerializer(serializers.Serializer):
    """
    value serializer the inner most of the payload
    """
    item = serializers.CharField()
    verb = serializers.CharField()
    reaction_type = serializers.CharField()
    created_time = serializers.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(4086831600)]
    )  # Limit the maximum epoch to 2099 July 4th 7:00AM
    post_id = serializers.CharField(max_length=40)
    from_key = FromSerializer()
    parent_id = serializers.CharField()

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass


FacebookReactionSerializer._declared_fields["from"] = FromSerializer(source="from_key")

我现在可以添加from作为密钥。但它不会从验证逻辑中删除from_key

(Pdb) serializer
FacebookReactionSerializer(data={'item': 'reaction', 'verb': 'add', 'reaction_type': 'like', 'created_time': 1516183830, 'post_id': '1331351323541869_1844740022202994', 'from': {'name': 'Krittuch Onnom', 'id': '1639217166122728'}, 'parent_id': '1331351323541869_1844740022202994'}):
    item = CharField()
    verb = CharField()
    reaction_type = CharField()
    created_time = IntegerField(validators=[<rest_framework.compat.MinValueValidator object>, <rest_framework.compat.MaxValueValidator object>])
    post_id = CharField(max_length=40)
    from_key = FromSerializer():
        name = CharField()
        id = CharField()
    parent_id = CharField()
    from = FromSerializer(source='from_key'):
        name = CharField()
        id = CharField()
(Pdb) serializer.is_valid()
False
(Pdb) serializer.errors
{'from_key': ['This field is required.']}

问题:
from(保留字)是key并且该键是python类属性时,您的解决方法是什么?

1 个答案:

答案 0 :(得分:1)

@cezar非常感谢你! 解决方案很简单!我很早就感到困惑。因为给定的解决方案使用ModelSerializer,所以必须放置fields并与模型属性耦合。

在我的例子中是简单Serializer我不需要其中任何一个。

从现在开始,我会通过Serializer

攻击这类问题
class FacebookReactionSerializer(serializers.Serializer):
    """
    value serializer the inner most of the payload
    """
    item = serializers.CharField()
    verb = serializers.CharField()
    reaction_type = serializers.CharField()
    created_time = serializers.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(4086831600)]
    )  # Limit the maximum epoch to 2099 July 4th 7:00AM
    post_id = serializers.CharField(max_length=40)
    parent_id = serializers.CharField()

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass


FacebookReactionSerializer._declared_fields["from"] = FromSerializer()

这是我的调试行

(Pdb) serializer
FacebookReactionSerializer(data={'item': 'reaction', 'verb': 'add', 'reaction_type': 'like', 'created_time': 1516183830, 'post_id': '1331351323541869_1844740022202994', 'from': {'name': 'Krittuch Onnom', 'id': '1639217166122728'}, 'parent_id': '1331351323541869_1844740022202994'}):
    item = CharField()
    verb = CharField()
    reaction_type = CharField()
    created_time = IntegerField(validators=[<rest_framework.compat.MinValueValidator object>, <rest_framework.compat.MaxValueValidator object>])
    post_id = CharField(max_length=40)
    parent_id = CharField()
    from = FromSerializer():
        name = CharField()
        id = CharField()
(Pdb) serializer.is_valid()
True