【问题标题】:Get value of another field in Field level Validation in DRF在 DRF 中的字段级验证中获取另一个字段的值
【发布时间】:2016-08-01 16:00:35
【问题描述】:

我在我的序列化程序中使用Field level Validation,并且在验证第二个字段时我需要第一个字段的值。我知道在object level validation 我可以访问它,但我的 serailzer 有many=True 并且在对象级别验证中我无法告诉客户端哪个迭代引发了错误。

Serailzer:

class Keys_Serializer(serializers.Serializer):
    """
    """
    key_id = serializers.IntegerField(required=True)
    key_name = serializers.CharField(required=True)
    value_id = serializers.IntegerField(required=False)

    def validate_key_id(self, value):
        """
        validate key id
        """
         *** validate key_id here ***
        return value

    def validate_value_id(self, value):
        """
        validate value_id w.r.t key_id
        """
         *** I need key_id of current iteration here so that I can validate value_id. ***
        return value

有没有办法在 value_id 验证中访问 key_id 的值。

【问题讨论】:

  • 你使用的是哪个版本的 Django Rest Framework?
  • @MuhammadShoaib djangorestframework==3.2.2
  • 您可以尝试使用 self.otherfieldname 访问然后验证吗?在 DRF 版本 attrs,然后您可以使用 attr['field_name'] 简单地访问其他值。但我不确定如何在 >3 版中执行此操作
  • @MuhammadShoaib 没有attrs parms 在 > 3 中。
  • 你试过使用 self.field_name 吗?

标签: django django-rest-framework


【解决方案1】:

不,那是不可能的。如果您需要访问多个值,则必须使用 Object-level validation (see docs):

class Keys_Serializer(serializers.Serializer):

    key_id = serializers.IntegerField(required=True)
    key_name = serializers.CharField(required=True)
    value_id = serializers.IntegerField(required=False)

    def validate(self, data):
        # here you can access all values
        key_id = data['key_id']
        value_id = data['value_id']
        # perform you validation
        if key_id != value_id:
            raise serializers.ValidationError("key_id must be equal to value_id")
        return data

【讨论】:

  • 是的,我知道我可以在对象级验证中访问它,以及为什么我不能使用我的问题中提到的那个。所以我只是想知道是否有任何钩子或其他东西可以让我访问其他值?
  • @Wtower,实际上你可以,尽管文档中没有提到。我挖了一下drf的代码库。您可以使用 self.get_initial() 轻松访问所有字段值。你可以找我的答案。
  • @user5594493,是的,有一个钩子。看我的回答。
  • 如果指定了 'many=True',所提供的解决方案将不起作用。
【解决方案2】:

我稍微研究了一下 drf 的代码库。您可以使用以下方法获取所有字段的值。这样你就可以将序列化错误抛出为{'my_field':'error message} 而不是{'non_field_error':'error message'}

def validate_myfield(self, value):
   data = self.get_initial() # data for all the fields
   #do your validation

但是,如果您希望为ListSerializer 执行此操作,即为serializer = serializer_class(many=True),则此操作无效。您将获得空值列表。在这种情况下,您可以在 def validate 函数中编写验证,并在序列化错误中避免 non_field_errors,您可以将错误消息作为字典而不是字符串引发 ValidationError

def validate(self, data):
    # do your validation
    raise serializers.ValidationError({"your_field": "error_message"})

【讨论】:

  • 不再适用于 3.11.1。所有值都是空的。
  • 在 3.12.2 中工作正常。
  • 是的,这种方法更好的原因是错误被抛出的方式;作为 field_error 而不是 non_field_error
【解决方案3】:
def validate(self, validated_data):
        """
        validate and verifies the user data before getting saved.
        :param validated_data: dict obj
        :return: validated_data
        """

        existing_data = self.to_representation(self.instance)

【讨论】:

    【解决方案4】:

    因此,如果您正在执行创建或更新普通未经验证的数据,则可以访问:

    self.context['view'].get_serializer().data
    

    虽然其他解决方案实际上更简洁,但我们在分区表上只有一个模型,并且需要另一个指定分区的字段,因为我们没有在主键上进行分区,数据库不知道如何查找它.

    编辑:看起来该字段实际上是空白的,您可能会遇到以下情况,这取决于序列化程序的使用方式(为此它必须在 ViewSet 中使用)

    self.context['view'].get_serializer().context['request'].data
    

    【讨论】:

      【解决方案5】:
      def validate_fieldname(self, value):
         data = self.context['request'].data
      

      【讨论】:

        【解决方案6】:

        另一个简单的解决方案是访问以下属性

        class Keys_Serializer(serializers.Serializer):
        
        key_id = serializers.IntegerField(required=True)
        key_name = serializers.CharField(required=True)
        value_id = serializers.IntegerField(required=False)
        
        def validate_key_name(self, value):
            #getting other field values as below
            self.initialdata
            #scrape data from initialdata
            # incase of updation time use 
            # self.instance and self.inistialdata together to get respective ones
            return  value
        
            
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-30
          • 2011-09-20
          • 2020-11-13
          • 1970-01-01
          • 2020-09-06
          • 2018-09-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多