我有Order对象和OrderOperation对象代表对订单的操作(创建、修改、取消)。
从概念上讲,一个订单有一对多的订单操作。每次对订单进行操作时,都会在此操作中计算总数。这意味着当我需要找到一个订单的总数时,我只得到最后一个订单操作的总数。
简化的代码
class OrderOperation(models.Model):
order = models.ForeignKey(Order)
total = DecimalField(max_digits=9, decimal_places=2)
class Order(models.Model):
@property
def last_operation(self) -> Optional['OrderOperation']:
try:
qs = self.orderoperation_set.all()
return qs[len(qs) - 1]
except AssertionError: # when there is a negative indexing (no operation)
# IndexError can not happen
return None
@property
def total(self) -> Optional[Decimal]:
last_operation = self.last_operation
return last_operation.total if last_operation else None
问题
由于接到的订单很多,每次想做“总低于5欧元的订单”之类的简单过滤,需要很长时间,因为要浏览所有订单,使用如下,明显不好查询:
all_objects = Order.objects.all()
Order.objects.prefetch_related('orderoperation_set').filter(
pk__in=[o.pk for o in all_objects if o.total <= some_value])
我目前的想法/我尝试过的
数据非规范化?
我可以简单地创建一个total属性 on Order,并在每次创建操作时将操作总数复制到订单总数中。然后,Order.objects.filter(total__lte=some_value)会工作。但是,在我的数据库中复制数据之前,我想确保没有更简单/更清洁的解决方案。
使用 annotate() 方法?
不知何故,我希望能够做到:Order.objects.annotate(total=something_magical_here).filter(total__lte=some_value)。好像是不可能的。
单独过滤然后匹配?
order_operations = OrderOperation.objects.filter(total__lte=some_value)
orders = Order.objects.filter(orderoperation__in=order_operations)
这非常快,但过滤很糟糕,因为我没有过滤最后的操作,而是这里的所有操作。这是错误的。
还有其他想法吗?谢谢。
隔江千里
相关分类