I am working on a django project and creating many model instances from batch upload form. I am creating many unsaved model instances in order to test them for errors as I don't want to enter any instances until the user has submitted a full set of valid records to avoid unintentional duplications within the database. My question is whether there is a good reason to use either save(commit=False) or full_clean on the unsaved model instances. I am currently using full_clean, but not sure what the differences/benefits are of one versus the other.
Calling full_clean() is the correct way to validate a model instance.
from django.core.exceptions import ValidationError
try:
obj.full_clean()
except ValidationError:
# handle invalid object
When dealing with a model form, calling is_valid() will perform the model validation, so you don't have to call full_clean() manually.
Calling save() with commit=False doesn't perform model validation. Instead, it gives you the opportunity to change the object before you save it to the database. A common example is to set the user attribute to the user that is currently logged on.
Related
I am using Django 1.11, in one of my models I have added actions when the model is saved.
However I don't want these actions to be done when only a part of the model is saved.
I know that update_fields=('some_field',) can be used to specify which field must be saved.
But, when the object has been fetched in the database using the methods only() or defer() I don't see any information about the fields updated in the save() method, update_fields is empty.
Thus my question: How can I get the fields saved by Django when only some fields have been fetched ?
When you use defer or only to load an instance, the get_deferred_fields() method returns a list of field names that have not been loaded; you should be able to use this to work out which ones will be saved.
I'm working on the importing script that saves data from CSV to Django database. Saving process looks like this:
instance = ModelName(**kwargs)
instance.save()
# No errors reported
But when I try to edit and save some items using admin panel it shows me a message that some of the field values (like URL fields and custom validators) is not valid.
Question: Is there any way to validate model instance from the python code using Django admin validators?
The issue is save() does not validate by default.
To address this, you can call the model's full_clean method to validate before calling save.
So, under the hood,
This method calls Model.clean_fields(), Model.clean(), and
Model.validate_unique() (if validate_unique is True), in that order
and raises a ValidationError that has a message_dict attribute
containing errors from all three stages.
The code would look something like this:
instance = ModelName(**kwargs)
instance.full_clean() #Does validation here
instance.save()
I have overwritten clean() methods for some of my models to construct constraints to meet my DB schema requirements (Because it required runtime information for those validations).
Since now I have finished most of the back-end side components(models, signals, ..) now I'm trying to write ModelForms for my models.
What I'm wondering is that, is there any relationship between the clean() method of model and clean() implementation on the form side?
If so and form's clean() calls model's clean() I won't have to rewrite my model - side clean() implementation and be able to avoid code redundancy.
Yes, ModelForm cleaning involves model cleaning. That's the idea with a ModelForm: there are a lot of useful defaults that can be determined by auto building a form object from a model.
I've discovered this clean chaining through personal experience, but to back it up I can reference the source.
On 1.8, ModelForms call the model instance full_clean method. On 1.7, it calls the clean method directly.
Form.full_clean()
def full_clean(self):
# ..... snip
self._clean_fields()
self._clean_form()
self._post_clean()
ModelForm._post_clean for 1.8
Model full_clean() calls clean() amongst other validation: https://docs.djangoproject.com/en/1.8/ref/models/instances/
self.instance.full_clean(exclude=exclude, validate_unique=False)
ModelForm._post_clean for 1.7
self.instance.clean()
According to Model.clean and ModelForms clean, I don't think there is any relationship between them.
These two clean has the same name but they did a different job.
Model.clean is used to validate the data you are going to store into database, and make sure the data is ok and can be stored into database.
This method should be used to provide custom model validation, and to modify attributes on your model if desired.
ModelForms clean, by my understanding, is to validate what the user has entered, and make sure they are ok.
You can override the clean() method on a model form to provide additional validation in the same way you can on a normal form.
And on a normal form, it's:
Implement a clean() method on your Form when you must add custom validation for fields that are interdependent.
And I think this one is also what you wanted:
Notice that we are talking about the clean() method on the form here, whereas earlier we were writing a clean() method on a field. It’s important to keep the field and form difference clear when working out where to validate things. Fields are single data points, forms are a collection of fields.
I think Django's model validation is a little inconvenient for those models that don't use built-in ModelForm, though not knowing why.
Firstly, full_clean() needs called manually.
Note that full_clean() will not be called automatically when you call
your model’s save() method, nor as a result of ModelForm validation.In
the case of ModelForm validation, Model.clean_fields(), Model.clean(),
and Model.validate_unique() are all called individually.You’ll need to
call full_clean manually when you want to run one-step model
validation for your own manually created models.
Secondly, validators are used in built-in ModelForm.
Note that validators will not be run automatically when you save a
model, but if you are using a ModelForm, it will run your validators
on any fields that are included in your form.
There are great demands when you need to do data validation before saving data into databases. And obviously I'd prefer to make it in model, rather than views. So, are there any good ideas to implement this gracefully in Django 1.5?
Even though the idea of enforcing validation on Model level seems right, Django does not do this by default for various reasons. Except for some backward-compatibility problems, the authors probably don't want to support this because they fear this could create a false feeling of safety when in fact your data are not guaranteed to be always validated. Some ORM methods (e.g. bulk_create or update) don't call save() and thus are unable to validate your models.
In other words, it is hard to guarantee the validation, thus they've decided not to pretend it.
If you need this for multiple models, you can create a simple mixin that overrides the save() method and calls full_clean() before super. Do note that this might cause the validation to be run twice in some cases, like when using ModelForm. It might not be that of an issue though if your validation routines are side-effect free and cheap to run.
For more info, please see these answers:
https://stackoverflow.com/a/4441740/2263517
https://stackoverflow.com/a/12945692/2263517
https://stackoverflow.com/a/13039057/2263517
I want to display error message in case the instance I am creating is more than the maximum limit I have specified in a certain model. This is a inner condition.
I know that we can hide the + and override the has_add_permission method. This is used for user authentication in my application.
However, I wish to allow the instance to be created for a certain login who is a superuser based on the inner condition.
ValidationError gives me error u' max...' ValidationError at the url...
Can anyone guide?
I don't know what an "inner condition" is.
However, you don't do this in the save method. You do it in a validator. For instance, you could define a clean method on your model to handle this, or use a custom form with the validation in.