Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#27782 closed Cleanup/optimization (needsinfo)

Model signals and Many2Many fields

Reported by: Дилян Палаузов Owned by: nobody
Component: Documentation Version: 1.10
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The documentation for Django 1.10 concerning signals is unclear when a models.ManyToManyField is updated, if the signal listeners of both models will be triggered, or only the listeners of one of the models.

class A(models.Model):

    i = models.IntegerField()

class B(models.Model):

    j = models.ManyToMayField(A)

@receiver(post_save, sender=B)
def X(sender, instance, created, kwargs):

    print("X triggered")

@receiver(post_save, sender=A)
def Y(sender, instance, created, kwargs):

    print("Y triggered")

a = A.objects.create(i=1)
b = B.objects.create()
b.j.add(i)
b.save()

Will this call both X() and Y(), as both models are equally updated?

Change History (8)

comment:1 by Tim Graham, 7 years ago

I'm not sure what would imply that A's post_save signal is sent considering there aren't any calls to a.save(). Could you point to the unclear documentation and suggest a clarification?

comment:2 by Дилян Палаузов, 7 years ago

With this model:

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class A(models.Model):
    i = models.IntegerField()

class B(models.Model):
    j = models.ManyToManyField(A)

@receiver(post_save, sender=A)
def XA(*args, **kwargs):
    print("XA")

@receiver(post_save, sender=B)
def XB(*args, **kwargs):
    print("XB")

I do

import my.models
a = my.models.A.objects.create(i=5)
b = my.models.B.objects.create()
b.j.add(a)

The first assignment prints XA and the second prints XB as expected.

The last line effectively modifies both objects - a and b - and persists the change. The latter means that a save() is called implicitly on both a and b, so I expect to see again XA and XB.

Or with other words, when a ManyToManyField is saved, what signals are sent from which model?

comment:3 by Tim Graham, 7 years ago

The latter means that a save() is called implicitly on both a and b

This is an incorrect assumption. Please read the docs for add().

comment:4 by Дилян Палаузов, 7 years ago

That is the point: the model is updated and there is no signal.

comment:5 by Tim Graham, 7 years ago

I'm not sure what to say besides what the documentation already says, "Using add() with a many-to-many relationship, however, will not call any save() methods." Creating a many-to-many relationship does not require saving any related objects. Instead the m2m_changed signal is sent.

Could you point to the unclear documentation and suggest a clarification?

comment:6 by Tim Graham, 7 years ago

Resolution: needsinfo
Status: newclosed

comment:7 by Дилян Палаузов, 7 years ago

I propose to repeat at the place where signals are described, that using add() does not trigger a signal.

comment:8 by Tim Graham, 7 years ago

Can you send a pull request with the proposal?

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