【问题标题】:Decorating a model class in django issuing save in the decorator在 django 中装饰模型类在装饰器中发出保存
【发布时间】:2011-12-15 05:21:30
【问题描述】:

我有几个模型可以将日志数据保存到我的数据库中。我还有一个“最近的事件”应用程序,我想选择哪些模型将数据发送到事件应用程序。我认为装饰器会对此有好处,所以我可以将它添加到我想要的模型中:

@logger
class TemperatureLog(models.Model):
    Date = models.DateTimeField(auto_now_add=True)
    Device = models.ForeignKey(TemperatureDevice)
    Data = models.PositiveIntegerField()

这是事件模型,我使用通用外键:

class Event(models.Model):
    Active = models.BooleanField()
    Queue = models.BooleanField()
    ContentType = models.ForeignKey(ContentType)
    ObjectID = models.PositiveIntegerField()
    Event = generic.GenericForeignKey('ContentType', 'ObjectID')

这里是装饰器:

def logger(event):
    def wrap(*args, **kwargs):
        from toolbox.event.models import Event
        event(*args, **kwargs).save()
        myid = event(*args, **kwargs).id
        new = Event(Event=event.objects.get(id=myid))

        if Event.objects.all().filter(Active=True).count() >= 25:
            new.Queue = True
            new.save()

        else:
            new.Active = True
            new.save()

            for item in Event.objects.all().filter(Queue=True):
                item.Queue = False
                item.Active = True
                item.save()

                if  Event.objects.all().filter(Active=True).count() >= 25:
                    break
        return event(*args, **kwargs)

    return wrap

它可以正常工作,它创建事件实例并保存它。我遇到的问题是 save() 会被调用两次。一个在装饰器中,第二个在收集温度日志的实际代码中(因为我不会提前知道哪些应用程序会发送事件,哪些不会,或者它们将来是否会改变)。所以我想知道是否有更优雅的方法来做到这一点。我喜欢装饰器方法,因为我所要做的就是将它添加到模型类中,但我不太相信 save 会被调用两次。

【问题讨论】:

    标签: python django django-models decorator


    【解决方案1】:

    对您问题的“原则上”回答是考虑使用the pre_save signal built into Django

    基本上,您将侦听器函数连接到pre_save 信号,完整记录在上面的链接中,您可以在模型实例上修改所需的属性。只有在您的侦听器完成执行(以及在该模型上连接到pre_save 的任何其他侦听器)之后,模型实例才会保存到数据库中。

    如果我正确理解您的代码,您希望您的 Queue 变量设置为 True 当且仅当数据库中有 25 个或更多活动事件记录,否则 False (@987654328 则相反@ -- 为什么你需要两个我不明白的布尔值)。你可以通过做这样的事情来用信号做到这一点......

    from django.db.signals import pre_save
    
    def update_event_active_queue_status(sender, instance=None, **kwargs):
        if Event.objects.filter(Active=True).count() >= 25:
            instance.Queue = True
        else:
            instance.Active = True
    pre_save.connect(update_event_active_queue_status, sender=Event)
    

    您尝试解决的另一个问题是,当活动事件的数量低于 25 时,将排队的事件移回活动状态。我不知道您的确切需求,但我可能会在 cron 工作或其他一些事件管理器上完成,而不是在这里解决。现在,如果没有事件被添加到系统中(或以其他方式更改),项目将永远不会被拉出队列。这可能不是你想要的。

    当然,您比我更了解您的需求,所以请谨慎对待我的建议。

    【讨论】:

      【解决方案2】:

      如何为所有模型使用 post_save 信号

      def log_saved_event(sender, instance, signal, *args, **kwargs):
          # handle Event class
          pass
      
      from django.db.models import signals
      from django.db import models
      
      for m in models.get_models():
          signals.post_save.connect(log_saved_event, sender=m)
      

      【讨论】:

        猜你喜欢
        • 2015-11-18
        • 2019-09-01
        • 1970-01-01
        • 2012-03-20
        • 2015-10-23
        • 2014-04-08
        • 2012-02-29
        • 1970-01-01
        • 2010-10-29
        相关资源
        最近更新 更多