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.