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

7👍

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.

👤wim

14👍

I dug around codebase of drf a little bit. You can get values of all fields using following approach. Doing so, you can throw serialization error as
{'my_field':'error message} instead of {'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, i.e for serializer = serializer_class(many=True), this won’t work. 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(self, data):
    # do your validation
    raise serializers.ValidationError({"your_field": "error_message"})
 

3👍

You can use the required package for your cross-field validation. It allows you to express your validation rules declaratively in python. You would have something like this with 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.

Here is a blog post explaining more

Leave a comment