Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. 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.

I'd like to apply the same validation to forms and REST calls, so I want to move my validation into the model. 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. 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?

like image 711
AnotherHowie Avatar asked Oct 18 '16 17:10

AnotherHowie


People also ask

How do I validate fields in Django?

The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class. It returns True if data is valid and place all data into a cleaned_data attribute.

What can be used to validate all model fields if any field is to be exempted from validation provide it in the exclude parameter?

clean_fields() method documentation: This method will validate all fields on your model. The optional exclude argument lets you provide a list of field names to exclude from validation. It will raise a ValidationError if any fields fail validation.

What is clean method in Django?

The clean_<fieldname>() method is called on a form subclass – where <fieldname> is replaced with the name of the form field attribute. This method does any cleaning that is specific to that particular attribute, unrelated to the type of field that it is. This method is not passed any parameters.

What does validators do in the code field validators?

A validator is a function that takes in the fields new value, and then acts on it. They are a simple way to customize a field. They allow you to trigger functionality when a field's value changes, modify input, or limit which values are acceptable.


2 Answers

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.

like image 80
wim Avatar answered Oct 06 '22 22:10

wim


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"})
 
like image 33
Sagar Adhikari Avatar answered Oct 06 '22 23:10

Sagar Adhikari