#python #django #django-models #decorator
#python #django #django-модели #декоратор
Вопрос:
У меня есть несколько моделей, которые сохраняют данные журнала в моей базе данных. У меня также есть приложение «недавние события», и я хотел бы выбрать, какие модели отправляют данные в приложение events. Я подумал, что для этого подойдет декоратор, поэтому я мог бы просто добавить его к нужным моделям:
@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 вызывается дважды.
Ответ №1:
Ответ «в принципе» на ваш вопрос заключается в том, чтобы рассмотреть возможность использования pre_save
сигнала, встроенного в Django.
По сути, вы подключаете функцию прослушивателя к pre_save
сигналу, полностью документированную по ссылке выше, и вы можете изменять нужные свойства в своем экземпляре модели. Только после завершения выполнения вашего слушателя (а также любых других слушателей, подключенных к pre_save
этой модели) экземпляр модели будет сохранен в базе данных.
Если я правильно понимаю ваш код, вы хотите, чтобы ваша Queue
переменная была установлена True
тогда и только тогда, когда в базе данных есть 25 или более записей активных событий, и 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)
Отдельная проблема, которую вы пытаетесь решить, и я не думаю, что это подходящее место для нее, — это перемещение событий в очереди обратно в режим active, когда количество активных событий падает ниже 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)