代码之家  ›  专栏  ›  技术社区  ›  joe

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

  •  3
  • joe  · 技术社区  · 6 年前

    这可能是一个关于眨眼的简单问题。但我无法完成。 我现在正在创建 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')
    

    不起作用

    尝试2:

    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
    

    Testcase失败此处是断点

    (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.']}
    

    尝试3:
    同时添加“”_声明的\u字段['from\u 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.']}
    

    我快到了,但这还不够

    尝试4.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\U键 从验证逻辑中退出

    (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.']}
    

    问题:
    您的解决方法是什么 从…起 (保留字)是 key 这个键是python类属性吗?

    1 回复  |  直到 6 年前
        1
  •  3
  •   joe    6 年前

    @塞萨尔非常感谢!
    解决方案非常简单!早期我很困惑。因为给定的解决方案使用 ModelSerializer 所以你必须 fields 以及与模型特性的耦合。

    在我的例子中是赤裸裸的平原 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