Django's ModelForms are cool, but I'm having trouble wrapping my head around why you'd ever want to put data integrity rules in your forms, when they could just be in the models themselves, per https://stackoverflow.com/a/18876223/1207253, who goes on to write "This isn't done by default, as explained here, because it interferes with certain features..."
I've read through the cited links and https://github.com/danielgatis/django-smart-save and still don't understand why this isn't the recommended approach. What are the features this approach interferes with? Excluded fields works. Default values works. What am I missing?
Only downside I can think of is that full_clean or clean (whichever you call in save) will be called twice if saving models through admin. There shouldn't be any side effects as such.
Form validation puts restriction on how the user enters data, Model validation specifies how that data must be processed / validated further before storing it in the db. So, unless your forms are very complicated, validating in the model works just fine.
Use whichever you are most comfortable with and adhere to it throughout the project as there is no strong convention here.
Related
Using:
django 1.10 reversion 2.0.8.
My question is how to show a nice list of changes done to a given model instance. By that I mean that the user can quickly see a list of all the changes (new values for fields) in all revisions. He doesn't need o see all the fields only the new values of the changed ones.
So I found that a good tool for storing changes is django-reversion. However, I cannot find a solution for my problem which as I mentioned is to show a nice change-log history for a given model instance.
I found solution that can compare two revisions django-reversion-compare, but that is not what I am looking for. Maybe there is a better tool for that ?
The task is too quickly show to user what was changed by who and when. The model is simple and doesn't store a lot of data. It does store however foreign keys.
I was also looking to do the same, and after reading up a few SO posts, docs etc., it seems I had to roughly choose the solution from one of the following 3 approaches:
1) Fetch the existing model instance before saving the new model instance. Compare each field. Put the changed field in reversion.set_comment('(all changes here)'). Continue with saving the model instance.
2) Save a copy of the old fields separately in model's __init__() and later compare the new fields with them (in model's save()) to track what changed. Put the changed fields in reversion.set_comment('(all changes here)'). Continue with saving the model instance. (This approach will save a DB lookup)
3) Generate a diff using django-reversion's low-level API and integrate with the Admin somehow
I ended up using django-reversion-compare which worked great for me showing the edits wiki-style (which may be using (3) above anyways)
django-reversion's developer also confirmed (3) as a better option which also avoids race condition.
If you would like to explore different options, this is a great SO post with lots of good ideas with their pros/cons.
(I am also on Django 1.10)
Django Rest Framework serializers do not call the Model.clean when validating model serializers. The explanation given is that this leads to 'cleaner separation of concerns', from the Django Rest Framework 3.0 release notes:
Differences between ModelSerializer validation and ModelForm.
This change also means that we no longer use the .full_clean() method
on model instances, but instead perform all validation explicitly on
the serializer. This gives a cleaner separation, and ensures that
there's no automatic validation behavior on ModelSerializer classes
that can't also be easily replicated on regular Serializer classes.
But what concerns are the authors of Django Rest Framework attempting to separate?
My guess is that they're saying that a model instance should not be concerned about it's own validity. If that's the case I don't understand why.
There are two major issues with the model's "full_clean".
The first one is technical. There are a couple of cases where the full_clean isn't called at all. For example, you'll bypass it when you do a queryset.update().
The second one is that if you have a complex business logic - which is usually why you'll have a full_clean - it's likely that you should do the validation in the business logic, not go down to the models to validate.
Each layer should be responsible for its own consistency and the storage layer - ie models - shouldn't care about the business layer.
Another thing that I can think of is that full_clean will be called once you have a model that comes after the serializer has been doing its validation. At this point, things start getting messy because you have a two-step validation with an object created in between.
If you're using nested serializer, you might be stuck here because you won't be able to create nested models before the primary model has been saved which will make the full clean call even messier - some objects will be created, others will not. It's hard to figure out when and what object should be validated with their full_clean and you can be sure there'll be a lot of complaints from users when they'll override the update/clean and figure out the full_clean hasn't been called for every model.
This started becoming a total headache and we prefer to keep things simpler and more explicit.
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 am trying to make my Django app follow better practices than it currently does. I hear about fat models and thin controllers a lot (after putting much of my display logic in views.py initially).
Anyway, say I have a moderately complex form, for creating new objects, including foreign keys on the new objects. Assuming there are no validation errors, where should the logic for creating / linking models go? views.py after is_valid() seems the easiest place to put, but I am not sure if that is considered best practice.
In the question title you describe it as "form processing logic", but it sounds from your question text like you really mean inter-model business logic.
If it's form processing logic (cleaning, etc.), that should go on the form.
Since it sounds like you're talking about business logic, it should generally be added to the appropriate model as a model method (Django docs on model methods), then called from either the custom form logic (e.g., on save) or from the view.
Of course, where the code lives depends to a great degree on the structure of relationship between your models. Say you have an author model with a one-to-many relationship to a book model. The author model might have a method that helps you create a new book object, filling in the foreign key relation as it goes. A more complex relationship might require more view code, or at least more thought.
And yes, in general it's a good idea to try to keep your views slimmer and your models fatter.
I'm pretty novice so I'll try to explain in a way that you can understand what I mean.
I'm coding a simple application in Django to track cash operations, track amounts, etc.
So I have an Account Model (with an amount field to track how many money is inside) and an Operation Model(with an amount field as well).
I've created a model helper called Account.add_operation(amount). Here is my question:
Should I include inside the code to create the new Operation inside Account.add_operation(amount) or should I do it in the Views?
And, should I call the save() method in the models (for example at the end of Account.add_operation() or must it be called in the views?)
What's the best approach, to have code inside the models or inside the views?
Thanks for your attention and your patience.
maybe you could use the rule "skinny controllers, fat models" to decide. Well in django it would be "skinny views".
To save related objects, in your case Operation I'd do it in the save() method or use the pre_save signal
Hope this helps
Experienced Django users seem to always err on the side of putting code in models. In part, that's because it's a lot easier to unit test models - they're usually pretty self-contained, whereas views touch both models and templates.
Beyond that, I would just ask yourself if the code pertains to the model itself or whether it's specific to the way it's being accessed and presented in a given view. I don't entirely understand your example (I think you're going to have to post some code if you want more specific help), but everything you mention sounds to me like it belongs in the model. That is, creating a new Operation sounds like it's an inherent part of what it means to do something called add_operation()!