views:

182

answers:

5

Hi all,

I use django and I wonder in what cases where model validation should go. There are at least two variants:

  1. Validate in the model's save method and to raise IntegrityError or another exception if business rules were violated
  2. Validate data using forms and built-in clean_* facilities

From one point of view, answer is obvious: one should use form-based validation. It is because ORM is ORM and validation is completely another concept. Take a look at CharField: forms.CharField allows min_length specification, but models.CharField does not. Ok cool, but what the hell all that validation features are doing in django.db.models? I can specify that CharField can't be blank, I can use EmailField, FileField, SlugField validation of which are performed here, in python, not on RDBMS. Furthermore there is the URLField which checks existance of url involving some really complex logic.

From another side, if I have an entity I want to guarantee that it will not be saved in inconsistent state whether it came from a form or was modified/created by some internal algorithms. I have a model with name field, I expect it should be longer than one character. I have a min_age and a max_age fields also, it makes not much sense if min_age > max_age. So should I check such conditions in save method?

What are the best practices of model validation?

A: 

I am not sure if this is best practise but what I do is that I tend to validate both client side and server side before pushing the data to the database. I know it requires a lot more effort but this can be done by setting some values before use and then maintaining them.

You could also try push in size contraints with **kwargs into a validation function that is called before the put() call.

AutomatedTester
A: 

Your two options are two different things.

  • Form-based validation can be regarded as syntactic validation + convert HTTP request parameters from text to Python types.
  • Model-based validation can be regarded as semantic validation, sometimes using context not available at the HTTP/form layer.

And of course there is a third layer at the DB where constraints are enforced, and may not be checkable anywhere else because of concurrent requests updating the database (e.g. uniqueness constraints, optimistic locking).

Vinay Sajip
A: 

There's an ongoing Google Summer of Code project that aims to bring validation to the Django model layer. You can read more about it in this presentation from the GSoC student (Honza Kral). There's also a github repository with the preliminary code.

Until that code finds its way into a Django release, one recommended approach is to use ModelForms to validate data, even if the source isn't a form. It's described in this blog entry from one of the Django core devs.

piquadrat
+1  A: 

"but what the hell all that validation features are doing in django.db.models? "

One word: Legacy. Early versions of Django had less robust forms and the validation was scattered.

"So should I check such conditions in save method?"

No, you should use a form for all validation.

"What are the best practices of model validation?"*

Use a form for all validation.

"whether it came from a form or was modified/created by some internal algorithms"

What? If your algorithms suffer from psychotic episodes or your programmers are sociopaths, then -- perhaps -- you have to validate internally-generated data.

Otherwise, internally-generated data is -- by definition -- valid. Only user data can be invalid. If you don't trust your software, what's the point of writing it? Are your unit tests broken?

S.Lott
That's a pretty idealistic assumption. I often have to work with data sources where the original creator had a less than rigorous approach to data validation. I still have to validate them before putting the data into my database, even though they don't come directly from a form. And that's why I'm longing so much for the result of the model validation GSoC project :-)
piquadrat
@piquadrat: You're talking about external data -- effectively from a user. Yes, it came from a database, but it's outside your application. It's not internal data generated by your application.
S.Lott
@S.Lott: Yes, exactly. But since the data doesn't originate from a web form, it seems clunky to validate the data through a form. Model validation will hopefully make such abuse unnecessary once it lands in Django trunk.I guess all I'm saying is that there are other sources of faulty data than web forms...
piquadrat
@piquadrat: Disagree. Forms are for validation. The API for validating data from other sources is very, very nice. Use it all the time.
S.Lott
A: 

DB/Model validation

The data store in database must always be in a certain form/state. For example: required first name, last name, foreign key, unique constraint. This is where the logic of you app resides. No matter where you think the data comes from - it should be "validated" here and an exception raised if the requirements are not met.

Form validation

Data being entered should look right. It is ok if this data is entered differently through some other means (through admin or api calls). Examples: length of person's name, proper capitalization of the sentence...

Example1: Object has a StartDate and an EndDate. StartDate must always be before EndDate. Where do you validate this? In the model of course! Consider a case when you might be importing data from some other system - you don't want this to go through.

Example2: Password confirmation. You have a field for storing the password in the db. However you display two fields: password1 and password2 on your form. The form, and only the form, is responsible for comparing those two fields to see that they are the same. After form is valid you can safely store the password1 field into the db as the password.

drozzy