Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django signals not working properly

Tags:

django

signals

I'm trying to setup a signal so that when a valid form is saved, a function is ran to carry out a related task.

My app structure is as follows;

- events
    - helpers
        - __init__.py
        - status.py
    - models
        - signals
            - __init__.py
            - event.py
        - __init__.py
        - event.py
        - status.py
    - views
        - __init__.py
        - event.py

I believe signals need to be imported as early as possible, before models, so at the top of models/__init__.py I've got from .signals import *.

# views/event.py
class AddEventView(CreateView):
    """
    View for adding an Event.
    """
    model = Event
    form_class = EventForm
    success_url = reverse_lazy('events:all_events')

    def form_valid(self, form):
        self.object = form.save()

        signals.event_status.send(
            sender=None, request=self.request, event=self.object, status=None
        ) # Should the sender be self.object?

        return super(AddEventView, self).form_valid(form)

# signals/event.py
from django.dispatch import Signal
event_status = Signal(providing_args=["request", "event", "status"])

# helpers/status.py
from ..models import Status, StatusHistory
from ..models.signals import event_status


def create_status(sender, **kwargs):
    """
    Create a status for a given event.
    """
    event = kwargs['event']
    status = kwargs['status']
    creator = User.objects.get(pk=event.creator)
    try:
        current_status = StatusHistory.objects.filter(
            event=event).order_by('timestamp')[0]
    except IndexError:
        # Not sure what we're doing here yet.
        pass
    if not status:
        status = Status.objects.get(description=_("Submitted"))

    statushistory = StatusHistory.create(
        event=event,
        event_status=status,
        user=creator
    )
    statushistory.save()

event_status.connect(create_status)

I'm running the debug server in Pycharm with a break point in the create_status() function & it's never getting hit.

Have I implemented this wrong?

like image 256
markwalker_ Avatar asked Nov 20 '14 11:11

markwalker_


3 Answers

I've used signals in some of my projects and I allways import the signals in the __init__.py of my Django APP (Same folder as settings.py, views.py, urls.py...)

__init__.py:

import signals

signals.py:

from django.db.models.signals import post_save, pre_delete 
from django.dispatch import receiver
from my_project.models import *


@receiver(post_save, sender=Modelname)  # Called after an object is saved
def create_modelname(sender, **kwargs):
    obj = kwargs['instance']  # I get the object being saved here
    # ... Here I do whatever I want

@receiver(pre_delete, sender=Modelname)  # Called before an object is deleted
def delete_modelname(sender, **kwargs):
   obj = kwargs['instance']
   # ... Do whatever you need

Remember this 2 imports:

  • from django.db.models.signals import post_save, pre_delete
  • from django.dispatch import receiver

Remember to import the signals

  • To import the signals you need to add import signals in your __init__.py of your project

Using this code, this functions are called automatically by Django when an object of the class Modelname is created or deleted.

The receiver for created object is called after the object is created, and the receiver for deleted object is called before the object is deleted.

like image 158
AlvaroAV Avatar answered Nov 07 '22 21:11

AlvaroAV


I think maybe you just need to import your helpers/status.py eg in models/__init__.py

otherwise your event_status signal gets defined ok but the signal handler create_status never gets connected by Django

if you only have one handler for that signal it might make sense to put it in the same module as the signal definition

like image 20
Anentropic Avatar answered Nov 07 '22 22:11

Anentropic


I found one case that signal is not working.

Here are cases that signal(pre_save, post_save) won't happen.

Model.objects.filter(pk=pk).update(key=value)

Bulk model functions won't happen signals.

like image 29
smartworld-dm Avatar answered Nov 07 '22 23:11

smartworld-dm