On Tuesday 24 January 2017 17:50:39 Bernd Wechner wrote:
> I find myself in a conundrum with related models and related formsets.
> I'll try and simplify a rather complex set of relations to illustrate
> the bare bones gist of my issue. Imagine the standard Djnago docs
> example:
> 
> class Musician(models.Model):
>     first_name = models.CharField(max_length=50)
>     last_name = models.CharField(max_length=50)
>     instrument = models.CharField(max_length=100)
> 
> class Album(models.Model):
>     artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
>     name = models.CharField(max_length=100)
>     release_date = models.DateField()
>     num_stars = models.IntegerField()
> 
> 
> Now imagine I have a form in which I can create (or update, same
> issues arise) a Musician and their Albums. I have a generic
> CreateView of Musician and on it a formset of Albums. You can enter a
> Musician's name and data and their albums and submit and it creates
> the objects in the database. All this I have working fine. Can even
> us JS to dynamically alter the formset and allow submission of any
> number of albums, and updated (with an UpdateView) of such record
> families.
> 
> Further, note that in Musician a field is created, "album_set" that is
> the set of Albums associated with that Musician.
> 
> Now I can put a clean() method in Musician, and it's works really
> charmingly. If I raise a ValidattionError in clean() the form
> re-renders with the message displayed (it's available in the context
> item "messages"). I love this it's very slick and easy.
> 
> Now let's say I have a criterion to enforce, say "A musician must have
> at least one album."

So, this criterion boils down to:
* the submitted inline album form has one or more albums OR
* the musician exists and has one or more albums

Order of the logic may differ pending the common case, but validation will be:
     *  Inspect the form count[1] of the album form set (total minus initial). 
This may 
require tweaking (added empty rows, duplicates) but you get the gist. Valid if 
> 0.
         *  Get the musician from the database, using whatever uniquely 
identifies a 
musician in the main form. Typical queryset.get() in a try block. Valid if 
exists and 
album_set is not None.
             *  Invalid

This can be done in the main view's form_valid().

I do not see a solid way to handle this at the model level, because you will 
have to 
save at least an album to validate the rule and both the artist and an album in 
the 
case of a new artist.
If you define a through model (in case this is a ManyToMany), you can query 
that 
model directly instead of having to go through a possibly missing attribute.
The same applies to querying the Album model directly (in case it is a reverse 
foreign 
key).

However this still means that it will yield no results if either the artist 
does not exist or 
no albums for the artist exist. The model has no clear path to validate the 
incoming 
data of a related model - that's what the form should do.

>From a higher level - it is trivial to generate a list of artists without 
>albums, so maybe 
implementing a procedure that generates that list for content maintainers to 
process 
is the better way to guard integrity, since that also covers the case of a DBA 
"deleting 
all albums before 1970".

-- 
Melvyn Sopacua

--------
[1] 
http://localhost/doc/py-django/html/topics/forms/formsets.html#total-form-count-and-initial-form-count

-- 
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 post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/2743741.ReKe00rmEF%40devstation.
For more options, visit https://groups.google.com/d/optout.

Reply via email to