I have Order
物体和OrderOperation
代表订单操作(创建、修改、取消)的对象。
从概念上讲,一个订单有一对多的订单操作。每次对订单进行操作时,都会在该操作中计算总计。这意味着当我需要查找订单的属性时,我只需使用子查询获取最后一个订单操作属性。
简化的代码
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>]>
or even:
>>> Order.objects.annotated_ordered_articles()[0].oo_ordered_articles
[42,43]
那可以解决我的问题。
我目前的想法
- 也许像ArrayAgg(我正在使用 pgSQL)可以做到这一点,但我不确定在我的情况下如何使用它。
- 也许这与
values()
该方法似乎无意处理文档中所述的 M2M 和 1TM 关系:
value() 和values_list() 都旨在作为优化
特定用例:检索数据子集,而无需开销
创建模型实例。这个比喻在处理问题时就站不住脚了
多对多和其他多值关系(例如一对多
反向外键的关系)因为“一行,一个对象”
假设不成立。