2012-05-24 2 views
4

У меня есть модель, которая выглядит следующим образом:Django, как представляется, кэширование datetime.now()

class Item(models.Model): 
    ... 
    publish_date = models.DateTimeField(default=datetime.datetime.now) 
    ... 

и менеджер, который выглядит следующим образом:

from datetime import datetime 

class ItemManager(Manager): 
    def published(self): 
     return self.get_query_set().filter(publish_date__lte=datetime.now() 

и вид, который выглядит как это:

class ItemArchive(ArchiveIndexView): 
    queryset = Item.objects.published() 
    date_field = 'publish_date' 

идея заключается в том, что я могу назвать Item.objects.published() и получить QuerySet из всех опубликованных Items.

Проблема заключается в том, что Django выполняет вызов datetime.now() в менеджере при запуске сервера и затем кешировании этого значения. Так что если сегодня 24 мая, и я создал Item с датой публикации от 23 мая и начал сервер 22 мая, этот 23 мая элемент не будет отображаться в представлении ItemArchive. Как только я перезапускаю Apache, 23 мая элемент отображается правильно.

Как заставить Django выполнить команду datetime.now() при каждом вызове менеджера?

ответ

12

Я считаю, что это вызвано тем, что ваш вид определяет queryset = Item.objects.published() как переменную класса. Эта строка будет выполнена один раз, когда ваш класс ItemArchive будет импортирован. Вы должны переместить эту строку в метод, где он будет выполняться каждый раз при вызове вида.

+2

Да. Или определите отдельный PublisherManager, который переопределяет 'get_query_set'. Это будет лениво, тогда как ваш «опубликованный» метод не будет. –

+1

Это, безусловно, сработает. Лучшая техника будет зависеть от контекста. Если действительно имеет смысл иметь 'queryset' как переменную класса, то предложение Даниэля было бы лучше. Тем не менее, ваш код может быть более читабельным, если вы просто вызываете 'Item.objects.published()' везде, где вы сейчас используете 'queryset'. – dgel

+0

Спасибо вам обоим! Мне потребовалось немного переделать, но оба решения имеют смысл. Я думаю, что dgel более уместен в моем контексте. – user1272534

0

Во-первых, просто использовать models.DateTimeField(auto_now_add=True)

Отредактировано:

Во-вторых, использовать get_queryset метод:

class ItemArchive(ArchiveIndexView): 
    date_field = 'publish_date' 

    def get_queryset(self): 
     return Item.objects.published() 
+0

Я не хочу использовать 'auto_now_add', потому что я хочу дать пользователям возможность редактировать дату публикации. Overwriting 'get_queryset' - это то, что предложил dgel в его ответе. Я думаю, это решение. Благодаря! – user1272534

3

Не использовать переменную queryset класса и переопределить get_queryset вместо этого. В общем, я думаю, что queryset - это немного красная селедка. Если вы просто указали model, Django автоматически устанавливает запрос в self.model.objects.all(). Если вам нужна фильтрация, в 99 раз из 100 вам нужно переопределить get_queryset, чтобы быть потокобезопасным. Вместо этого попробуйте следующее.

class ItemArchive(ArchiveIndexView): 
    model = Item 
    date_field = 'publish_date' 

    def get_queryset(self): 
     return super(ItemArchive, self).get_queryset().published() 
Смежные вопросы