Django聚合筛选器

4

我有三个类似下面的模型,我想要在一个查询中获取我的物品的最新销售日期,这是使用SQL肯定可以实现的,但我正在尝试使用内置的Django功能:

class Item(models.Model):
    name = models.CharField()
    ...

class InventoryEntry(models.Model):
    delta = models.IntegerField()
    item = models.ForeignKey("Item")
    receipt = models.ForeignKey("Receipt", null=True)
    created = models.DateTimeField(default=timezone.now)
    ...

class Receipt(models.Model):
    amt = models.IntegerField()
    ...

我所要做的是查询我的物品并注明它们上一次销售的时间。可以通过查询InventoryEntry模型来确定某个记录是否为销售记录,基于收据的存在(库存也可能因为订单、被盗等原因而调整,但我只关心最近一次销售)。
我的查询目前看起来像这样,目前只能获取任何库存条目的最新值。我想筛选注释,仅在InventoryEntry上receipt__isnull=False时返回created的最大值:
Item.objects.filter(**item_qs_kwargs).annotate(latest_sale_date=Max('inventoryentry_set__created'))

我尝试使用When查询表达式,但它没有按预期工作,可能是我误用了它。希望能得到任何有见地的建议。


我有一个解决方法,使用RawSQL对象,但如果可能的话,我宁愿不在其中使用自己的SQL。 - Titus P
您还没有实际尝试使用When。 - e4c5
我认为没有必要发布因为它没有按预期工作。我希望有人知道如何得到我所问的问题,我发布不起作用的内容并不会有太多帮助。如果你有想法,我很乐意尝试并发布结果。 - Titus P
filter(**item_qs_kwargs)后面加上filter(inventoryentry__receipt__isnull=False)无法正常工作? - Aziz Alfoudari
2个回答

3
一个使用条件表达式的解决方案应该像这样工作:
from django.db.models import Max, Case, When, F

sale_date = Case(When(
    inventoryentry__receipt=None,
    then=None
), default=F('inventoryentry__created'))
qs = Item.objects.annotate(latest_sale_date=Max(sale_date))

我会尝试一下并告诉你。 - Titus P
很好的答案。只是一个小提示:没有F表达式也可以正常工作。也就是说:default='inventoryentry__created'。如果我漏掉了什么,请纠正我。 - Carlos Mermingas
这似乎按照我的要求工作!谢谢!我要指出的是,它的性能不是很好(尝试在此上运行.query,它并不理想!)而且我正在使用的rawsql查询,虽然我认为Django可以轻松复制它,但实际上效果要好得多。我现在可能会坚持使用性能更好的那个,并将这个留在口袋里以备将来之需。 - Titus P

0

我尝试了一些修改过的解决方案。看看吧。

from django.db.models import F

Item.objects\
.annotate(latest_inventoryentry_id=Max('inventoryentry__created'))\
.filter(
inventoryentry__id=F('latest_inventoryentry_id'), 
inventoryentry__receipt=None
)

我没有手动检查。你可以检查并让我知道。

谢谢


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接