save_m2m() does not honor save_instance's exclude argument
|Reported by:||margieroginski||Owned by:||melinath|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
save_m2m() does not seem to honor the exclude argument that is passed in to save_instance. I have a form that includes a particular m2m field, however I am trying to avoid saving that field. To do this I am setting self._meta.exclude explicitly, just prior to calling the form's save method. After saving the task, I do the standard save_m2m() to save the m2m fields. I find that non-m2m fields are correctly excluded from the save if specified in this way via self._meta.exclude, but that m2m fields are not excluded from the save if specified this way. This seems inconsistent.
I suppose it could be rejected as a bug based on the fact that exclude is a model meta attribute, and if used exactly as specified in the doc, I wouldn't have the field in my form at all, so this wouldn't come up.
Here is some background on what I am doing to make a case for fixing this. I have an app sort of like the admin app. Say I have a model called 'foo'. User A views it and user B views it. User A then changes field 'status', and saves it. User B then changes field 'priority' and saves it. I need to avoid having user B's save change the 'status' field, since user B didn't modify that field. I am using the hidden initial functionality to detect that user B has not changed the status field, and then I am setting self._meta.exclude to all fields in the form that were not changed by the user. This all works fine the fields are non-m2m fields, but breaks down when an m2m field is placed in self._meta.exclude.
Currently save_m2m() is defined like this:
def save_m2m(): opts = instance._meta cleaned_data = form.cleaned_data for f in opts.many_to_many: if fields and f.name not in fields: continue if f.name in cleaned_data: f.save_form_data(instance, cleaned_data[f.name])
I find that if I define it like this instead, the m2m fields correctly are omitted from the save if they are in exclude. This seems like more consistent and useful behavior to me.
def save_m2m(): opts = instance._meta cleaned_data = form.cleaned_data for f in opts.many_to_many: if fields and f.name not in fields: continue if exclude and f.name in exclude: <=== added this if clause continue if f.name in cleaned_data: f.save_form_data(instance, cleaned_data[f.name])
Change History (15)
comment:1 Changed 5 years ago by russellm
- Needs documentation unset
- Needs tests unset
- Patch needs improvement unset
- Resolution set to invalid
- Status changed from new to closed
- Triage Stage changed from Unreviewed to Accepted
comment:4 Changed 5 years ago by brainrape@…
- Resolution invalid deleted
- Status changed from closed to reopened
- Version changed from 1.1 to SVN
Changed 5 years ago by brainrape@…
comment:5 Changed 4 years ago by thejaswi_puthraya
- Component changed from Uncategorized to Database layer (models, ORM)
comment:9 Changed 3 years ago by melinath
- Component changed from Database layer (models, ORM) to Forms
- Owner changed from nobody to melinath
- Status changed from reopened to new