Джанго: Кэширование совокупного запроса? - PullRequest
4 голосов
/ 13 августа 2010

У меня есть модель Invoice, и я хочу постоянно обновлять total. Поэтому я добавил свойство, подобное этому

@property
def item_total(self):
    if not hasattr(self, 'item_total_cache'):
        self.item_total_cache = self.items.aggregate(t=Sum('amount'))['t']
    return self.item_total_cache

Поскольку item_total может вызываться несколько раз во время одного запроса страницы, и я не хочу каждый раз обращаться к БД. Это хороший способ сделать это? Будет ли мой Invoice объект существовать за пределами одного запроса страницы, и, таким образом, item_total может фактически устареть?

В идеале, я бы хотел вычислить item_total одновременно с запросом счетов-фактур ... Я знаю, что могу сделать это вручную, но сайт администратора Django, например, не знает, что он собирается нужна сумма. Могу ли я каким-то образом «добавить» этот дополнительный кусок информации, чтобы все Invoice.objects.all/filter/get() запросы выполняли агрегат одновременно?

Ответы [ 2 ]

4 голосов
/ 13 августа 2010

Могу ли я предложить другое решение?Почему бы не сохранить счет и не сделать его автоматическим приращением / уменьшением с помощью сигналов?

Это зависит от количества операций чтения / записи, которые вы имеете, но кэширование чего-то подобного, вероятно, является более эффективным решением.И возможно немного проще.

В любом случае, вы правильно кэшируете счет.Объект Invoice не должен устаревать, если вы не кешируете его каким-либо другим способом.Этот кеш привязан к экземпляру, и с новым запросом вы можете предположить, что вы также получите новый экземпляр.Если вы не получаете свои предметы из memcached, то есть.

Что касается инъекции в кеш при необходимости.Как это будет работать, если вы используете get() или filter()?В этом случае ваш счет будет ниже, а ваш кэш неверен.Это должно быть вполне выполнимо для all().Вы можете просто перезаписать менеджер по умолчанию, чтобы автоматически добавлять эти данные во время выборки.Но это будет означать, что для каждого Item, который вы запрашиваете, ваш Invoice будет также выбран.

3 голосов
/ 13 августа 2010

Это хорошее решение, которое я использовал и рекомендовал ранее. Ваш объект Invoice не будет сохраняться после одностраничного запроса, пока вы не сохраните ссылки на него в глобальной области видимости - если он просто создан в представлении и передан в шаблон, все будет хорошо.

Существует несколько способов заставить администратор сайта автоматически генерировать агрегат. Одним из них является определение собственного диспетчера и переопределение get_query_set для возврата self.annotate(Sum('amount')) - это гарантирует, что агрегат всегда будет создаваться для каждого отдельного запроса в модели счета-фактуры, что может не соответствовать вашему желанию.

Альтернативой является определение отдельного метода в менеджере - например, with_aggregate, который возвращает его, но затем переопределяет метод ModelAdmin get_queryset, чтобы вернуть результат этого метода. Это дает вам больше контроля, чтобы решить, использовать ли агрегат в ваших собственных представлениях.

...