Оформление модельного класса в django с выдачей сохранения в декораторе - PullRequest
1 голос
/ 25 октября 2011

У меня есть несколько моделей, которые сохраняют данные журнала в моей базе данных. У меня также есть приложение "Недавние события", и я хотел бы выбрать, какие модели отправляют данные в приложение событий. Я думал, что для этого подойдет декоратор, поэтому я мог бы просто добавить его к нужным моделям:

@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 () будет вызван дважды. Один в декораторе, а второй в реальном коде, который собирает журналы температуры (поскольку я заранее не знаю, какие приложения будут отправлять события, а какие - нет, и могут ли они измениться в будущем). Поэтому мне интересно, есть ли более элегантный способ сделать это. Мне нравится подход декоратора, так как все, что мне нужно сделать, это добавить его в класс модели, но я не очень убежден в необходимости сохранения вызова дважды.

Ответы [ 2 ]

1 голос
/ 25 октября 2011

«Принципиальный» ответ на ваш вопрос - рассмотреть возможность использования сигнала 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)

Отдельная проблема, которую вы пытаетесь решить, и я не думаю, что это подходящее место для этого, движетсясобытия в очереди возвращаются к активным, когда число активных событий падает ниже 25. Я не знаю ваших точных потребностей, но я бы, вероятно, сделал это на работе cron или каким-либо другим менеджером событий, а не рассматривал их здесь.Прямо сейчас, если в систему не будет добавлено ни одного события (или изменено каким-либо другим способом), элементы никогда не будут извлечены из очереди.Это, вероятно, не то, что вы хотите.

Конечно, вы знаете свои потребности лучше, чем я, поэтому примите мои рекомендации с долей соли.

0 голосов
/ 26 октября 2011

Как насчет использования сигнала 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)
...