On 25/07/2019 1:03 pm, Jim Illback wrote:
I had a slight variation on this thread - where to put some M2M field
validation/deletion logic.
I have a purely model-based form where a checkbox’s value determines
whether another field (it’s a M2M field) in the form should be NULL or
keep its values to be saved in the database. So, following the
appropriate separation of concerns as advocated below, I added logic
in both the models' clean and save override methods. Neither approach
set the other field to NULL when it should have been. The reason is
the form still contained M2M values even though the model said to
delete them (delete the set, actually).
There's a bit of trapeze happening here. The form is always in mid-air.
No matter what happens in the form the model save is only called when
all the validation (ie form first for the obvious errors then model for
business rules) has succeeded.
So, boolean (or any other) field values don't make it into the database
until model.save() succeeds.
And, the framework logic has to cope with database rejection of the
values as well. So the entire transaction needs to be able to roll back
if something goes awry at the last moment. Keep your eye on
transactions. I think PostgreSQL is probably the best of the open source
RDBMSs for that. I know Django seems to have no problems with it.
My typical approach in the model to see things before and after the save
is ...
def save(self, *args, **kwargs:
var_to_be_passed = self._pre_save()
super(ThisModel, self).save(*args, **kwargs)
self._post_save(var_to_be_passed)
I use self._post_save() usually to do additional database things like
creating child models.
If your user-initiated change relies on a value in the database then you
have to save it first so it gets there.
Also, remember that the model's clean() method is only ever called by
Django when a ModelForm is used. Otherwise you have to call it yourself.
That's where I put all my business rule validation. I typically have
separate mofel methods and just call thin in clean() and raise
validation errors if necessary. That is totally appropriate because a
Django form knows how to deal with them.
As I said previously, in unti tests you have to call clean() explicitly.
After a lot of trial and error, it turns out that the model’s save
seems to be run BEFORE the form’s save. To me, that seems backwards.
Shouldn’t the model’s processes (which are directly relate to the
database, the ultimate data source) occur last and well before the
form’s (which are merely an interaction with the user)? What was
happening was my model’s delete actually did the deletions (those IDs
were gone), but then the form’s processing came along afterwards and
re-inserted them again (with brand new IDs).
Can someone help me understand why Django has chosen this seemingly
“inversion” of processing - first models’ processes, then forms’? And,
perhaps more importantly, where should this either/or logic should be
placed so it will take effect?
Thanks very much,
Jim Illback
On Jul 13, 2019, at 11:48 PM, Mike Dewhirst <mi...@dewhirst.com.au
<mailto:mi...@dewhirst.com.au>> wrote:
Well yes it could be called multifaceted.
Usually but not always the interface with the user is the form. You
can have non-database fields as well as model fields so either way
there has to be a full suite of validation functionality available in
both types of forms. Luckily, model forms automatically call
model.clean() for you.
Unit tests don't though. You have deliberately call obj.clean() if
you want to test things. obj.save() doesn't call obj.clean().
Actually, I also do a bit in view code too especially if there are
non-database or hidden fields in the form. I know you are not
supposed to validate data in a view for proper separation of concerns
but it does keep my forms neater.
The bottom line for me is that if I can imagine non-form access ...
eg through an API ... then all validation possible has to be via
model.clean() and the API has to remember to call clean() before
saving every time there is a POST
Hence I*always*put business rules validation in model.clean() and
leave 'local' validation for the form.
You are right. There are quite a few moving parts<ic_list_happy.png>
/Connected by Motorola/
Dean Karres <dean.kar...@gmail.com <mailto:dean.kar...@gmail.com>> wrote:
Thank you. There are way more parts to this than I would have imagined.
On Sat, Jul 13, 2019, 8:01 PM Mike Dewhirst <mi...@dewhirst.com.au
<mailto:mi...@dewhirst.com.au>> wrote:
On 14/07/2019 10:37 am, Dean Karres wrote:
Hi,
I am learning Django. I am using CBVs. My default "index.py"
view is basically a dashboard for the app I am playing with. As
my models and views become more complicated I want to be able to
ask, for any model instance, is this instance "valid" or
"complete". Valid means that all Required elements are present
and have reasonable values. "Complete" means that an instance
is "valid" but also some specific bits of additional info are
also ok.
For example I have a Student model that has name and address
info. There is a ManyToMany relation to the Class(es) in which
that Student is enrolled. A "student" instance is valid if the
name and address fields are filled. A student is "complete" if
the student is valid and has signed up for one or more classes.
So, my question is: where should the valid and complete methods
live? Should they be in the Student model or CBV? Someplace
else? Does it matter?
I like to put that sort of stuff into model methods then add
model.clean() to call them and raise whatever error may be
appropriate if they fail.
https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#interaction-with-model-validation
and
https://docs.djangoproject.com/en/2.1/ref/models/instances/#validating-objects
and
https://docs.djangoproject.com/en/2.1/ref/models/instances/#django.db.models.Model.clean
You can raise your own errors which inherit from ValidationError
to fine tune the process. For example, I differentiate between
BusinessRuleViolation and InvalidToken and a couple of others
where that delivers better control.
Cheers
--
You received this message because you are subscribed to the
Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from
it, send an email todjango-users+unsubscr...@googlegroups.com
<mailto:django-users+unsubscr...@googlegroups.com>.
To post to this group, send email
todjango-us...@googlegroups.com
<mailto:django-users@googlegroups.com>.
Visit this group athttps://groups.google.com/group/django-users.
To view this discussion on the web
visithttps://groups.google.com/d/msgid/django-users/22801669-96ec-4a43-a264-fd50c2544604%40googlegroups.com
<https://groups.google.com/d/msgid/django-users/22801669-96ec-4a43-a264-fd50c2544604%40googlegroups.com?utm_medium=email&utm_source=footer>.
For more options, visithttps://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it,
send an email todjango-users+unsubscr...@googlegroups.com
<mailto:django-users+unsubscr...@googlegroups.com>.
To post to this group, send email todjango-us...@googlegroups.com
<mailto:django-users@googlegroups.com>.
Visit this group athttps://groups.google.com/group/django-users.
To view this discussion on the web
visithttps://groups.google.com/d/msgid/django-users/ajujeafh6d4qa4vvpfv2bxf9.1563085360028%40email.android.com
<https://groups.google.com/d/msgid/django-users/ajujeafh6d4qa4vvpfv2bxf9.1563085360028%40email.android.com?utm_medium=email&utm_source=footer>.
For more options, visithttps://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to django-users+unsubscr...@googlegroups.com
<mailto:django-users+unsubscr...@googlegroups.com>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-users/A2531CD5-E89E-4EB3-84C5-CF6CEB05E53D%40hotmail.com
<https://groups.google.com/d/msgid/django-users/A2531CD5-E89E-4EB3-84C5-CF6CEB05E53D%40hotmail.com?utm_medium=email&utm_source=footer>.
--
You received this message because you are subscribed to the Google Groups "Django
users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to django-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-users/0d2d8c7d-1dd5-fcf5-1355-c6c7ed09a07b%40dewhirst.com.au.