#29346: Add "intermediary" kwarg to ModelForm._save_m2m ---------------------------------------------+------------------------ Reporter: Douglas Denhartog | Owner: nobody Type: New feature | Status: new Component: Forms | Version: 2.0 Severity: Normal | Keywords: Triage Stage: Unreviewed | Has patch: 0 Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 0 | ---------------------------------------------+------------------------ This is my first ticket, so while I attempted to follow the applicable guidelines, I apologize in advance if this ticket is not a model guideline-following example.
---- Django's documentation clearly explain Intermediary Model limitations: "[u]nlike normal many-to-many fields, you can’t use add(), create(), or set() to create relationships" Thus, when `ModelForm.save()` is called and an intermediary model field is not in `self._meta.exclude`, users will get an error like so: {{{ Cannot set values on a ManyToManyField which specifies an intermediary model. Use app.IntermediaryModelName's Manager instead. }}} This presents complexity when the intermediary field is included in the form. My proposal is to add a kwarg `intermediary` to `ModelForm._save_m2m`. This kwarg behaves exactly like `self._meta.exclude` within `ModelForm._save_m2m`. I have already created a github branch with my solution, but have not created a pull request per contribution guidelines (but will do so if/when this ticket is approved). My solution adds three/four (3/4) lines of code, denoted in my solution below with EOL comment `# ADDED`. I believe my simple solution is more appropriate than a complex introspective analysis of every potential ManyToManyField's 'through' attribute. The final code of my proposal is (in django.forms.models): {{{ def _save_m2m(self, intermediary=None): # ADDED """ Save the many-to-many fields and generic relations for this form. """ # could assert/convert intermediary == str, list, tuple # ADDED cleaned_data = self.cleaned_data exclude = self._meta.exclude fields = self._meta.fields opts = self.instance._meta # Note that for historical reasons we want to include also # private_fields here. (GenericRelation was previously a fake # m2m field). for f in chain(opts.many_to_many, opts.private_fields): if not hasattr(f, 'save_form_data'): continue if fields and f.name not in fields: continue if exclude and f.name in exclude: continue if intermediary and f.name in intermediary: # ADDED continue # ADDED if f.name in cleaned_data: f.save_form_data(self.instance, cleaned_data[f.name]) }}} And yes, this means adding the `intermediary` kwarg to `ModelForm.save()` so that `intermediary` can be passed to `ModelForm._save_m2m`. -- Ticket URL: <https://code.djangoproject.com/ticket/29346> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/052.82d39bf5c6932c26ba5db9cc9766429c%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.