0

When the user creates a product, multiple actions have to be done in save() method before calling super(Product,self).save(*args,**kwargs).

I'm not sure if I should use just one pre_save signal to do all these actions or it is better to create a signal for each of these actions separately.

Simple example (I'm going to replace save overrides by signals):

class Product(..):
    def save(...):
        if not self.pk:
            if not self.category:
                self.category = Category.get_default()
            if not self.brand:
                self.brand = 'NA'
        super(Product,self).save(*args,**kwargs)
        ...

SO

@receiver(pre_save,sender=Product)
def set_attrs(instance,**kwargs):
    if kwargs['created']:
        instance.category = Category.get_default()
        instance.brand = 'NA'

OR

@receiver(pre_save,sender=Product)
def set_category(instance,**kwargs):
    if kwargs['created']:
        instance.category = Category.get_default()

@receiver(pre_save,sender=Product)
def set_brand(instance,**kwargs):
    if kwargs['created']:
        instance.brand = 'NA'

This is just simple example. In this case, the general set_attrs should be probably enough but there are more complex situations with different actions like creating userprofile for user and then userplan etc.

Is there some best practice advice for this? Your opinions?

Tejas Thakar
  • 585
  • 5
  • 19
Milano
  • 18,048
  • 37
  • 153
  • 353
  • I would say for maintainability it would be better to split them up. But I generally try to avoid using signals and instead use manager methods etc. – The_Cthulhu_Kid Jul 04 '17 at 10:47

1 Answers1

0

To put the facts out simply, it could be pointed out as a single piece of advice,

If action on one model's instance affects another model, signals are the cleanest way to go about. This is an example where you can go with a signal, because you might want to avoid some_model.save() call from within the save() method of another_model, if you know what I mean.

To elaborate on an example, when overriding save() methods, common task is to create slugs from some fields in the model. If you are required to implement this process on multiple models, then using a pre_save signal would be a benefit, rather than hard-coding in save() method of each models.

Also, on bulk operations, these signals and methods are not necessarily called.

From the docs,

Overridden model methods are not called on bulk operations

Note that the delete() method for an object is not necessarily called when deleting objects in bulk using a QuerySet or as a result of a cascading delete. To ensure customized delete logic gets executed, you can use pre_delete and/or post_delete signals.

Unfortunately, there isn’t a workaround when creating or updating objects in bulk, since none of save(), pre_save, and post_save are called.

For more reference,

Community
  • 1
  • 1
zaidfazil
  • 9,017
  • 2
  • 24
  • 47