【发布时间】:2019-07-18 16:39:58
【问题描述】:
我有 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() 都是为了优化 特定用例:检索数据子集而无需 创建模型实例。这个比喻在处理时分崩离析 多对多和其他多值关系(例如一对多 反向外键的关系),因为“一行,一个对象” 假设不成立。
【问题讨论】:
-
你想要的行为是什么?
-
@GwynBleidD 问题已更新为“目的”部分。
-
应该只从最后一个
OrderOperation得到它们吗? -
@GwynBleidD 是的。行为应该类似于
total。除了total在OrderOperation中返回一个简单的十进制值,而ordered_articles是多对多字段的管理器,所以我想处理起来更复杂:)
标签: python django django-queryset