Screwing up data
At a previous talk I gave on “Things I wish I’d known about Django” there was this slide:
I’ve made some experimental code in a small Django clean vs save project. It has a few models and a single test file which is readable and passes.
The main take-aways are:
- Creating an instance of a Model and calling save on that instance does not call full_clean. Therefore it’s possible for invalid data to enter your database if you don’t manually call the full_clean function before saving.
- Object managers’ default create function also doesn’t call full_clean.
Personally I find this jarring.
Given that the developer is the customer of Django I think it conflicts with the principle of least astonishment.
Why is it like this?
The Django documentation of Validating Objects is quoted in Django ticket #13100 as saying:
Note that full_clean() will NOT be called automatically when you call your model’s save() method. You’ll need to call it manually if you want to run model validation outside of a ModelForm. (This is for backwards compatibility.)
Ahh “backwards compatibility”?!
It appears that phrase only lived for four months back in 2010.
I haven’t been able to find any more specific reasons that it was added or removed.
More warnings I guess:
- Consider if you ever want to be able to call save without full_clean. If the answer is ‘no’, then explore how you’ll wrap your models in business logic or extend them in some way that implements this (with tests of course). A quick search of the internet will show you some Django plugins that adjust this behaviour.
- Remember that you can ruin your database when migrating if you don’t call full_clean after the migration has changed a model but before saving. All migrations should be tested to ensure that they can roll-back if full_clean raises a ValidationError during migration.
- Check out posts like Why I sort of dislike Django. It mentions things like backwards compatibility and the save function.
Thanks to PXG for sharing the “Why I sort of dislike Django” post and discussing Django project structures with me.
Thanks for reading!