简体   繁体   English

根据另一个字段的值验证 Django 模型字段?

[英]Validating a Django model field based on another field's value?

I have a Django app with models accessible by both Django REST Framework and a regular form interface.我有一个 Django 应用程序,其模型可通过 Django REST 框架和常规表单界面访问。 The form interface has some validation checks before saving changes to the model, but not using any special Django framework, just a simple local change in the view.表单界面在保存对模型的更改之前有一些验证检查,但不使用任何特殊的 Django 框架,只是在视图中进行简单的本地更改。

I'd like to apply the same validation to forms and REST calls, so I want to move my validation into the model.我想对表单和 REST 调用应用相同的验证,所以我想将我的验证移到模型中。 I can see how to do that for simple cases using the validators field of the Field, but in one case I have a name/type/value model where the acceptable values for 'value' change depending on which type is selected.我可以看到如何使用 Field 的验证器字段在简单情况下执行此操作,但在一种情况下,我有一个名称/类型/值模型,其中“值”的可接受值根据选择的类型而变化。 The validator doesn't get sent any information about the model that the field is in, so it doesn't have access to other fields.验证器不会收到有关该字段所在模型的任何信息,因此它无权访问其他字段。

How can I perform this validation, without having essentially the same code in a serializer for DRF and my POST view for the form?如何在 DRF 的序列化程序和表单的 POST 视图中没有本质上相同的代码的情况下执行此验证?

I dug around codebase of drf a little bit.我稍微挖掘了一下 drf 的代码库。 You can get values of all fields using following approach, though it is not mentioned in docs.您可以使用以下方法获取所有字段的值,但文档中未提及。 Doing so, you can throw serialization error as {'my_field':'error message} instead of {'non_field_error':'error message'} .这样做,您可以将序列化错误作为{'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

However, if you wish to do it for ListSerializer, ie for serializer = serializer_class(many=True) , this won't work.但是,如果您希望为 ListSerializer 执行此操作,即对于serializer = serializer_class(many=True) ,这将不起作用。 You will get list of empty values.您将获得空值列表。 In that scenario, you could write your validations in def validate function and to avoid non_field_errors in your serialization error, you can raise ValidationError with error message as a dictionary instead of string.在这种情况下,您可以在def validate函数中编写验证并避免序列化错误中的non_field_errors ,您可以使用错误消息作为字典而不是字符串来引发ValidationError

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

The validation per-field doesn't get sent any information about other fields, when it is defined like this:当按如下方式定义时,每个字段的验证不会发送有关其他字段的任何信息:

def validate_myfield(self, value):
    ...

However, if you have a method defined like this:但是,如果您有这样定义的方法:

def validate(self, data):
    ...

Then you get all the data in a dict, and you can do cross-field validation.然后你在一个字典中得到所有的数据,你就可以做跨领域的验证了。

You can use the required package for your cross-field validation.您可以使用所需的包进行跨领域验证。 It allows you to express your validation rules declaratively in python.它允许您在 python 中声明性地表达您的验证规则。 You would have something like this with DRF:使用 DRF 你会有这样的事情:

class MySerializer(serializers.Serializer):

    REQUIREMENTS = (
        Requires("end_date", "start_date") +
        Requires("end_date", R("end_date") > R("start_date")) + 
        Requires("end_date", R("end_date") < today.date() + one_year) + 
        Requires("start_date", R("start_date") < today.date() + one_year)
     )

    start_date = serializers.DateField(required=False, null=True, blank=True)
    end_date = serializers.DateField(required=False, null=True, blank=True)

    def validate(self, data):
        self.REQUIREMENTS.validate(data)  # handle validation error

You could put the REQUIREMENTS on your Model and have both your DRF and Django Form validate your data using it.您可以将REQUIREMENTS放在您的模型上,并让您的 DRF 和 Django 表单使用它来验证您的数据。

Here is a blog post explaining more是一篇解释更多的博客文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM