【问题标题】:Call a function after Django model save/delete is called在调用 Django 模型保存/删除后调用函数
【发布时间】:2015-10-16 11:09:44
【问题描述】:

我在 Django 中有很多模型类。它们都没有被覆盖的 save() 或 delete() 函数。

我想创建一个类级别的装饰器,用于在调用 save() / delete() 后执行一个函数。这个类级别的装饰器应该是通用的,以便所有模型类都可以使用它。

我已经尝试使用 post_save 和 post_delete 的信号,但是维护大量的类列表可能是个问题。我也想避免覆盖 save()/delete()。

关于如何去做的任何建议?提前致谢。

【问题讨论】:

    标签: python django decorator


    【解决方案1】:

    推荐使用 post_save 信号。

    如果您不想单独注册每个模型类,这里有一个使用类装饰器的解决方案:

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    class SaveRegister:
        registered_classes = []
        post_save_func = None
    
        @classmethod
        def register(cls, target_cls):
            if not cls.post_save_func:
                raise Exception("Post save function not defined")
            if target_cls not in cls.registered_classes:
                # prevent duplicate registration
                cls.registered_classes.append(target_cls)
                # register the model class to listen to post_save
                receive(post_save, sender = target_cls)(cls.post_save_func)
    
        # set the post_save signal handler
        @classmethod
        def set_post_save_func(cls, f):
            cls.post_save_func = f
    

    现在您所要做的就是定义一个 post_save 处理程序,将其设置到 SaveRegister 类中:

    def model_post_save(sender, **kwargs):
        print('Saved an instance with type: {}'.format(sender))
    SaveRegister.set_post_save_func(model_post_save)
    

    每个用SaveRegister.register 修饰的模型类都会自动拥有一个 post_save 处理程序:

    @SaveRegister.register
    class Student(SignaledModel):
        number = models.PositiveIntegerNumber(unique=True)
        name = models.CharField(max_length=64)
    
    @SaveRegister.register
    class Course(SignaledModel):
        code = models.CharField(unique=True)
        teacher = models.CharField(max_length=64)
    

    【讨论】:

    • 谢谢尼奥。我不想维护模型列表。所以我正在尝试一种不同的方法。
    【解决方案2】:

    您是否尝试过创建 abstract 模型类并从中继承所有实际模型?这样,当您将pre_save 信号附加到基类时,只要保存了任何子模型,就会发送该信号。

    class SignaledModel(models.Model):
        class Meta:
            abstract = True
    
    class Student(SignaledModel):
        number = models.PositiveIntegerNumber(unique=True)
        name = models.CharField(max_length=64)
    
    class Course(SignaledModel):
        code = models.CharField(unique=True)
        teacher = models.CharField(max_length=64)
    

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    @receiver(post_save, sender=SignaledModel)
    def model_post_save(sender, **kwargs):
        print('Saved an instance with type: {}'.format(sender))
    

    每当保存CourseStudent 实例时,都会调用model_post_save

    希望这会有所帮助。

    【讨论】:

    • 感谢您的示例。它解决了维护大量模型的问题。只是出于好奇,我们有什么方法可以使用类级别的装饰器来完成它?
    • 我不这么认为,因为save 方法是一个实例方法换句话说,它与“self”一起工作 因此,实现一个没有意义用于此目的的类级别装饰器。
    • 我尝试将pre_save 信号附加到基类,但没有成功。您能否在帖子中包含信号的代码?我也试过different approach
    • 我应该将基类中的pre_save 信号连接到哪个处理程序?
    猜你喜欢
    • 1970-01-01
    • 2017-08-26
    • 2014-10-21
    • 2018-11-20
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多