У меня есть Order
объекты и OrderOperation
объекты, которые представляют действие над заказом (создание, изменение, отмена).
Концептуально, заказ имеет от 1 до многих операций заказа.Каждый раз, когда есть операция с заказом, общая сумма вычисляется в этой операции.Это означает, что когда мне нужно найти атрибут заказа, я просто получаю последний атрибут операции заказа, используя подзапрос.
Упрощенный код
class OrderOperation(models.Model):
order = models.ForeignKey(Order)
total = DecimalField(max_digits=9, decimal_places=2)
class Order(models.Model)
# ...
class OrderQuerySet(query.Queryset):
@staticmethod
def _last_oo(field):
return Subquery(OrderOperation.objects
.filter(order_id=OuterRef("pk"))
.order_by('-id')
.values(field)
[:1])
def annotated_total(self):
return self.annotate(oo_total=self._last_oo('total'))
Таким образом, я могу запустить my_order_total = Order.objects.annotated_total()[0].oo_total
.Это прекрасно работает.
Проблема
Вычислить общее значение легко, поскольку это простая величина.Однако при наличии поля M2M или OneToMany этот метод не работает.Например, используя приведенный выше пример, давайте добавим это поле:
class OrderOperation(models.Model):
order = models.ForeignKey(Order)
total = DecimalField(max_digits=9, decimal_places=2)
ordered_articles = models.ManyToManyField(Article,through='orders.OrderedArticle')
Запись чего-то подобного НЕ работает, так как возвращает только 1 внешний ключ (не список всех FK):
def annotated_ordered_articles(self):
return self.annotate(oo_ordered_articles=self._last_oo('ordered_articles'))
Цель
Вся цель состоит в том, чтобы позволить пользователю выполнять поиск среди всех заказов, предоставляя список или статьи для ввода.Например: «Пожалуйста, найдите все заказы, содержащие хотя бы статью 42 или статью 43», или «Пожалуйста, найдите все заказы, содержащие точно статьи 42 и 43» и т. Д.
Если бы я мог получить что-то вроде:
>>> Order.objects.annotated_ordered_articles()[0].oo_ordered_articles
<ArticleQuerySet [<Article: Article42>, <Article: Article43>]>
или даже:
>>> Order.objects.annotated_ordered_articles()[0].oo_ordered_articles
[42,43]
Это решило бы мою проблему.
Моя текущая идея
- Может быть, что-тонапример,
ArrayAgg
(я использую pgSQL) может добиться цели, но я не уверен, что понимаю, как использовать его в моем случае. - Может быть, это связано с
values()
метод, который, по-видимому, не предназначен для обработки отношений M2M и 1TM, как указано в документе:
values () и values_list () оба предназначены в качестве оптимизации для конкретного использованияcase: извлечение подмножества данных без затрат на создание экземпляра модели.Эта метафора разваливается при работе со многими ко многим и другими многозначными отношениями (такими как отношение «один ко многим» обратного внешнего ключа), потому что предположение «одна строка, один объект» не выполняется.