Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django m2m_changed signal is never called

I can't understand why my m2m_changed signal is not triggered.

Here is the code:

models.py

class Badge(TimeStampable, Expirable, Deactivable,
            SafeDeleteModel):
    _safedelete_policy = HARD_DELETE

    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              blank=True, null=True,
                              on_delete=models.PROTECT)
    restaurants = models.ManyToManyField(Restaurant)
    identifier = models.CharField(max_length=2048)

    objects = SafeDeleteManager.from_queryset(BadgeQuerySet)()

signals.py

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

from .models import Badge

@receiver(m2m_changed, sender=Badge.restaurants.through)
def my_callback(sender, **kwargs):
    print("M2M has been changed!")

apps.py (this post advised to change this file)

from django.apps import AppConfig

class BadgesConfig(AppConfig):
    name = 'badges'

    def ready(self):
        import badges.signals

When going to a shell:

  • m2m_changed.receivers returns an empty list (it does not work, and the signal can never be received)

I found similar post but did not found the answer in it.

Why m2m_changed signal does not work?

EDIT

When opening a shell and importing badges.signals, it works. It means the problem is in apps.py:

In [1]: from django.db.models.signals import m2m_changed

In [2]: m2m_changed.receivers
Out[2]: []

In [3]: import badges.signals

In [4]: m2m_changed.receivers
Out[4]:
[((4551224720, 4520068792),
  <weakref at 0x10f4da5e8; to 'function' at 0x10f462d90 (check_uniqueness)>)]
like image 656
David D. Avatar asked May 31 '18 13:05

David D.


People also ask

How do you call a signal in Django?

Sending signals There are two ways to send signals in Django. To send a signal, call either Signal. send() (all built-in signals use this) or Signal. send_robust() .

What kind of signals are there in Django?

There are 3 types of signal. pre_save/post_save: This signal works before/after the method save(). pre_delete/post_delete: This signal works before after delete a model's instance (method delete()) this signal is thrown. pre_init/post_init: This signal is thrown before/after instantiating a model (__init__() method).

Should I use Django signals?

The only reason to use signalsOnly use signals to avoid introducing circular dependencies. If you have two apps, and one app wants to trigger behaviour in an app it already knows about, don't use signals. The app should just import the function it needs and call it directly.


1 Answers

I found my mistake in this section of Django the documentation. From the beggining, my apps configurations were never called!

Actually, to register an app correctly, I have two methods:

method 1

INSTALLED_APPS = ['badges', ...]

and declaring in __init__.py: default_app_config = 'badges.apps.BadgesConfig'

method 2

INSTALLED_APPS = ['badges.apps.BadgesConfig']

my mistake

I was using the INSTALLED_APPS = ['badges', ...] without declaring anything in __init__.py

I think maybe Django could display a warning when it notices that apps.py is in a folder app but never used.

like image 81
David D. Avatar answered Sep 20 '22 01:09

David D.