Opened 4 years ago

Closed 4 years ago

#29615 closed Cleanup/optimization (duplicate)

Document difference in behaviour between m2m_changed behaviour for add() vs remove() when called multiple times.

Reported by: nirmalraghavan Owned by: Sanyam Khurana
Component: Documentation Version: 2.0
Severity: Normal Keywords: signals, m2m_changed
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Consider the following Model,

class MyModel(models.Model):
    likes = models.ForeignKey(User)

Now if I add a user to the likes field as below,
myObj.likes.add(user)

my m2m_changed receiver method will be called in signals module with action post_add. And if I try to add the same user again. nothing will happen which is fine.

And when I try to remove the user as below,
myObj.likes.remove(user)

m2m_changed receiver method is called with action post_remove. And if I try to remove the same user again, this time also m2m_changed receiver method is called. Even if there's no such user exist in ManyToMany field, django will emit post_remove signal.

Change History (6)

comment:1 Changed 4 years ago by Carlton Gibson

Is this a duplicate of #22296?

comment:2 Changed 4 years ago by Carlton Gibson

Component: Database layer (models, ORM)Documentation
Keywords: signals m2m_changed added
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

OK, this is distinct from #22296.

There is an anomaly here. `add()` calls filter out the existing instances before processing the ids:

                vals = (self.through._default_manager.using(db)
                        .values_list(target_field_name, flat=True)
                        .filter(**{
                            source_field_name: self.related_val[0],
                            '%s__in' % target_field_name: new_ids,
                        }))
                new_ids.difference_update(vals)

This is necessary to avoid django.db.utils.IntegrityError: UNIQUE constraint failed ... errors.

No such problem exists with duplicate delete() calls, so no such filtering is done.

I'm guessing that the extra DB query would not be considered worth it to avoid the extra signal call here. (Anyone?)

But I think this probably could be documented as a note at the end of the `m2m_changed` reference.

comment:3 Changed 4 years ago by Carlton Gibson

Summary: post_remove action is called even though there's no relationDocument difference in behaviour between m2m_changed behaviour for add() vs remove() when called multiple times.

comment:4 Changed 4 years ago by Sanyam Khurana

Owner: changed from nobody to Sanyam Khurana
Status: newassigned

comment:5 Changed 4 years ago by Carlton Gibson

Patch needs improvement: set

comment:6 Changed 4 years ago by Tim Graham

Resolution: duplicate
Status: assignedclosed

As far as I can tell, the report that the m2m_changed signal isn't sent for redundant add() calls isn't correct. The signal is still sent on any subsequent add(), but pk_set is empty. This looks like a duplicate of #27462.

Note: See TracTickets for help on using tickets.
Back to Top