Tyrel's Blog

Code, Flying, Tech, Automation

Nov 13, 2013

How to not trigger a post_save in Django, but still modify data.

Recently I have been diving into using signals with Django, which of course are pretty neat.

I am working on a website for work which in the most basicexplanation, is a task management site. Recently I have added in the ability to subscribe to tasks and get emails, I did this by connecting to the post_save signal. I only email out when a task is changed, not created (of course, no one would be subscribed to it). This worked flawlessly and "emails" out to anyone who is subscribed. I say that in quotes, because I haven't actually hooked it up to a real SMTP server, and only use

python -m smtpd -n -c DebuggingServer localhost:1025

which will output any emails to stdout. But I digress… A problem arose when I was working on ordering tasks.

I store an integer in the "ordering" column, which any authenticated user can drag the row to a new location and that will reorder the task. I did this after I setup the emailing signal, so I didn't think about an email being sent out for EVERY task being changed.

I tried a lot of different things, and was debating some that would be a bit messy. Among those ideas were trying to store the past values in another table, but that would get expensive fast. The reason I tried this was because I wanted to see if the ordering was the only thing that changed, and if that was the case, not send an email. I eventually found a thread on StackOverflow that says to use update on the queryset to not trigger the signal.

You can do this by doing something like this:

from app.models import ModelName

def reorder(request):
    new_order = request.POST.get('new_order', None)
    pk = request.POST.get('modelname_pk', None)
    if new_order:
       ModelName.objects.filter(pk=pk).update(ordering=new_order)

I am not sure if this is the proper way save changes and not trigger a post_save signal, but this is the way that worked for me so I figured I would document this.

 · · ·  django  python