在 django 中装饰模型类并在装饰器中保存

发布于 2024-12-12 01:48:32 字数 1587 浏览 0 评论 0原文

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

@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 被调用两次。

I have several models that save log data to my database. I also have a "recent events" app and I would like to choose which models send data to the events app. I thought a decorator would be good for this, so I could just add it to the models I want:

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

Here is the events model, Im using generic foreign keys:

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

And here is the decorator:

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

It works as it should, it creates the event instance and saves it. The problem that I have is that save() would be called twice. One in the decorator and the second in the actual code that collects the temperature logs (since I wont know ahead of time which apps will send events and which wont or if they might change in the future). So I wonder if there is a more elegant way to do this. I like the decorator approach since all I have to do is add it to the model class, but I am not very convinced of having save being called twice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

厌味 2024-12-19 01:48:32

对您问题的“原则上”回答是考虑使用pre_save 内置于 Django 的信号

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

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

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 作业或其他事件管理器上完成此操作,而不是在此处解决。现在,如果没有事件添加到系统中(或以其他方式更改),则项目永远不会从队列中拉出。这可能不是你想要的。

当然,您比我更了解您的需求,所以请对我的建议持保留态度。

The "in principle" response to your question is to consider using the pre_save signal built into Django.

Basically, you connect a listener function to the pre_save signal, documented in full at the link above, and you can modify the desired properties on your model instance. Only after your listener finishes executing (as well as any other listeners connected to pre_save on that model) will the model instance be saved to the database.

If I understand your code correctly, you want your Queue variable set to True if and only if there are 25 or more active event records in the database, and False otherwise (with the opposite for Active -- why you need two booleans I don't understand). You could do that with signals by doing something like this...

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)

A separate problem that you're trying to solve, and I don't think this is the right place for it, is moving queued events back to active when the number of active events falls below 25. I don't know your exact needs, but I'd probably have that done on a cron job or by some other event manager, rather than being addressed here. Right now, if no events are added into the system (or changed in some other way), items would never be pulled out of queue. That's probably not what you want.

Of course, you know your needs better than I do, so take my recommendations with a grain of salt.

泛泛之交 2024-12-19 01:48:32

对所有模型使用 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)

How about using post_save signal for all models

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文