Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django model fields validation

Where should the validation of model fields go in django?

I could name at least two possible choices: in the overloaded .save() method of the model or in the .to_python() method of the models.Field subclass (obviously for that to work you must write custom fields).

Possible use cases:

  • when it is absolutely neccessary to ensure, that an empty string doesn't get written into the database (blank=False keyword argument doesn't work here, it is for form validation only)
  • when it is neccessary to ensure, that "choices" keyword argument gets respected on a db-level and not only in admin interface (kind of emulating a enum datatype)

There is also a class-level attribute empty_strings_allowed in the models.Field base class definition and derived classes happily override it, however it doesn't seem to produce any effect on the database level, meaning I can still construct a model with empty-string fields and save it to the database. Which I want to avoid (yes, it is neccessary).

Possible implementations are

on the field level:

class CustomField(models.CharField):     __metaclass__ = models.SubfieldBase     def to_python(self, value):         if not value:             raise IntegrityError(_('Empty string not allowed'))         return models.CharField.to_python(self, value) 

on the model level:

class MyModel(models.Model)     FIELD1_CHOICES = ['foo', 'bar', 'baz']     field1 = models.CharField(max_length=255,                 choices=[(item,item) for item in FIELD1_CHOICES])      def save(self, force_insert=False, force_update=False):         if self.field1 not in MyModel.FIELD1_CHOICES:             raise IntegrityError(_('Invalid value of field1'))         # this can, of course, be made more generic         models.Model.save(self, force_insert, force_update) 

Perhaps, I am missing something and this can be done easier (and cleaner)?

like image 809
shylent Avatar asked Oct 26 '09 13:10

shylent


People also ask

How can you validate Django model fields?

to_python() method of the models. Field subclass (obviously for that to work you must write custom fields). Possible use cases: when it is absolutely neccessary to ensure, that an empty string doesn't get written into the database (blank=False keyword argument doesn't work here, it is for form validation only)

How do I validate two fields in Django?

They go into a special “field” (called all), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specific field in the form, you need to call add_error(). So from Django documentation you can use add_error() to do what you want to achieve.

How does Django validate data?

Django forms submit only if it contains CSRF tokens. It uses uses a clean and easy approach to validate data. 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 is __ str __ In Django model?

The __str__() method is called whenever you call str() on an object. Django uses str(obj) in a number of places. Most notably, to display an object in the Django admin site and as the value inserted into a template when it displays an object.


1 Answers

Django has a model validation system in place since version 1.2.

In comments sebpiq says "Ok, now there is a place to put model validation ... except that it is run only when using a ModelForm! So the question remains, when it is necessary to ensure that validation is respected at the db-level, what should you do? Where to call full_clean?"

It's not possible via Python-level validation to ensure that validation is respected on the db level. The closest is probably to call full_clean in an overridden save method. This isn't done by default, because it means everybody who calls that save method had now better be prepared to catch and handle ValidationError.

But even if you do this, someone can still update model instances in bulk using queryset.update(), which will bypass this validation. There is no way Django could implement a reasonably-efficient queryset.update() that could still perform Python-level validation on every updated object.

The only way to really guarantee db-level integrity is through db-level constraints; any validation you do through the ORM requires the writer of app code to be aware of when validation is enforced (and handle validation failures).

This is why model validation is by default only enforced in ModelForm - because in a ModelForm there is already an obvious way to handle a ValidationError.

like image 85
Carl Meyer Avatar answered Oct 11 '22 00:10

Carl Meyer