Как сохранить назначенные атрибуты для объекта набора запросов после фильтрации? Альтернативы? - PullRequest
1 голос
/ 15 апреля 2019

Может быть, это странный ответ, поэтому я объясню, почему я делаю это.

У меня есть модель Продукты .Я должен назначить каждому из них акции .

Так что у меня есть функция для модели Products, которая рассчитывает множество необходимых вещей, таких как акции и возвращает QuerySe t.

Поскольку моя модель БД немного «сложная», в этом случае я не могу использовать аннотации.Поэтому я решил выполнить этот запрос к базе данных вручную, а затем назначить каждый продукт в запросе. Установить атрибут акции вручную .Что-то вроде:

for product in queryset_products:
    product.stock = some_stock_calc...

Проблема возникает, когда я хочу использовать filters this queryset_product.после выполнения чего-то вроде:

queryset_products = queryset_products.filter(...)

атрибут акции получает потерян

Любое решение?

Ответы [ 3 ]

0 голосов
/ 17 апреля 2019

Все операции над набором запросов, такие как .filter(), являются символическими, пока набор запросов не будет перечислен.Затем SQL-запрос компилируется и выполняется.Неэффективно вычислять запас по большому нефильтрованному набору запросов, а затем даже запускать его снова с фильтрацией.Вы можете разделить фильтр на условия, не связанные с запасом, добавленным к набору запросов, а затем фильтр, связанный с запасом, который вы оцениваете в том же цикле Python, где вы вычисляете запас.

result = []   
for product in queryset_products.filter(**simple filters):
    product.stock = some_stock_calc...
    if product.stock > 0 or not required_on_stock:
        result append(product)

Поле кэша возможных активныхпродукты, которые могут быть на складе, очень полезны для первого простого фильтра.

Возможно, расчет запаса не сложнее, чем, например, запас в полночь плюс сумма операций с запасами с полуночи.Затем текущий запас можно рассчитать с помощью Subquery в аннотации и отфильтровать вместе.Он будет скомпилирован в один SQL-запрос с основным запросом с присоединениями к связанным моделям и относительно простым подзапросом для акций.(Это был бы другой вопрос.)

0 голосов
/ 17 апреля 2019

Это может быть решено по-разному, вы можете запустить один цикл как

queryset_products = list(queryset_products.filter(...))

for product in queryset_products:
   setattr(product, "stock") = some_stock_calc...

По сути, вам нужно извлечь все записи из базы данных, так как запрос ленив, он будет потерян, так как он будет повторнооценивается, если результаты не были кэшированы / сохранены.

0 голосов
/ 15 апреля 2019

Поскольку вы не можете использовать annotate(), если вы можете добавить отдельный столбец для хранения stock в таблице Product, вы можете в любое время выполнить запросы filter. Может быть, есть задача celery, которая выполняет все вычисления для каждого Product и сохраняет в новый столбец.

В противном случае без annotate вы не можете иметь атрибут stock в наборе запросов.

...