jshcrm jshcrm - 16 days ago 4
Python Question

Django pre_save signals work when Model is saved but not ModelForm?

I created a pre_save signal to check if a field was updated before savings a model and shoot off a webhook if so. This works fine when I edit the model from ./manage.py shell and save it, but if I edit it on my site, which utilizes a form, it does not fire off the webhook. Why is this?

apps.py

from django.apps import AppConfig


class ClientConfig(AppConfig):
name = 'client'
verbose_name = "Clients"
label = 'client'

def ready(self):
import client.signals


signals.py

@receiver(pre_save, sender=ClientContact)
def send_hook_on_roadmap_update(sender, instance, **kwargs):
"""Watches for ClientContacts to be saved and checks to see if the
pipeline attribute has changed.
"""
try:
obj = sender.objects.get(pk=instance.pk)
except sender.DoesNotExist:
pass # Object is new, so field hasn't technically changed
else:
if not obj.pipeline == instance.pipeline: # Field has changed
instance.pipeline_updated()


models.py

class ClientContact(models.Model):
title = models.CharField(_("Title"), max_length=50, blank=True, null=True)
first_name = models.CharField(_("First name"), max_length=30, )
last_name = models.CharField(_("Last name"), max_length=30, )
email = models.EmailField(_("Email"), blank=True, max_length=75)
create_date = models.DateField(_("Creation date"))
address = models.ForeignKey('AddressBook', blank=True, null=True, on_delete=models.SET_NULL)
pipeline = models.ForeignKey(Pipeline, blank=True, null=True, on_delete=models.SET_NULL)


forms.py

class ContactModelForm(forms.ModelForm):
def __init__(self, client, organization, *args, **kwargs):
super(ContactModelForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
'first_name',
'last_name',
'title',
'email',
'address',
'pipeline',
)
self.helper.form_class = 'form-horizontal'
self.helper.form_method = 'post'
self.helper.html5_required = True
self.helper.add_input(Submit('contact_save', 'Save'))
self.fields['address'].queryset = AddressBook.objects.filter(organization=client)
self.fields['pipeline'].queryset = Pipeline.objects.filter(organization=organization)

class Meta:
model = ClientContact
fields = ('first_name', 'last_name', 'title', 'email', 'address', 'pipeline')

Answer

I'm not sure why it does not work, but I would suggest you to move that function to your models save method.

class ClientContact(models.Model):
    title = models.CharField(_("Title"), max_length=50, blank=True, null=True)
    first_name = models.CharField(_("First name"), max_length=30, )
    last_name = models.CharField(_("Last name"), max_length=30, )
    email = models.EmailField(_("Email"), blank=True, max_length=75)
    create_date = models.DateField(_("Creation date"))
    address = models.ForeignKey('AddressBook', blank=True, null=True, on_delete=models.SET_NULL)
    pipeline = models.ForeignKey(Pipeline, blank=True, null=True, on_delete=models.SET_NULL)

    def save(self, *args, **kwargs):
        #check if obj is new or being updated
        try:
            obj = ClientContact.objects.get(pk=self.pk)
            if not obj.pipeline == self.pipeline:  # Field has changed
                self.pipeline_updated()
        except ObjectDoesNotExist:
            pass
        #call super and store data
        super(ClientContact, self).save(*args, **kwargs)