Django聚合具有多个模型

Django聚合具有多个模型,django,Django,我有这些模型: class Package(models.Model): title = CharField(...) class Item(models.Model) package = ForeignKey(Package) price = FloatField(...) class UserItem(models.Model) user = ForeignKey(User) item = ForeignKey(Item) purchase

我有这些模型:

class Package(models.Model):
    title = CharField(...)

class Item(models.Model)
    package = ForeignKey(Package)
    price = FloatField(...)

class UserItem(models.Model)
    user = ForeignKey(User)
    item = ForeignKey(Item)
    purchased = BooleanField()
我正试图以尽可能最好的性能实现两个功能:

  • 在我的模板中,我想计算每个包裹所有物品的价格总和。(我猜是多少?)

  • 更复杂的是:我希望对于每个用户,我可以总结所有购买物品的价格。因此,购买的=真实

  • 假设我在一个包裹里有10件物品,每件都要10美元,那么包裹的总额应该是100美元。假设用户购买5件物品,第二笔金额应为50美元


    我可以轻松地使用TempleteTag进行简单查询,但我相信可以做得更好?(希望如此)

    要计算特定套餐的总价格,可以使用以下代码

    Item.objects.filter(package=a_package).aggregate(Sum('price'))
    
    有一个,和,具有所描述的所有不同功能

    这种查询还可以解决第二个问题

    UserItem.objects.filter(user=a_user).filter(purchased=True).aggregate(sum('price'))
    
    您还可以使用
    annotate()
    将计数附加到每个对象,请参见上面的第一个链接。

    我认为最优雅的方法是在模型类上定义一个方法
    total
    ,并将其装饰为一个新的方法。这将返回
    程序包
    用户
    总计
    (使用Django ORM)

    包的示例

    from django.db.models import Sum
    
    ...
    
    class Package(models.Model):
    
        ...
    
        @property
        def total(self):
            return self.item_set.aggregate(Sum('price'))
    
    在模板代码中,您将使用
    total
    作为任何其他模型属性。例如:

    {{ package_instance.total }}
    

    @维克·史密斯找到了答案

    但是如果您愿意,我会在
    模型上添加
    价格
    属性

    尽可能最好的表现

    您将在保存时向项添加一个
    信号,如果已创建,则更新相关的
    对象

    这样你可以很快得到包装价格,甚至可以进行快速排序、比较等

    另外,我并不真正了解购买的
    属性的用途。但是您可能希望在
    Item
    User
    之间建立多个关系,并将
    UserItem
    定义为与
    trhough
    参数的连接


    无论如何,我的经验是,您通常希望在
    项目
    采购
    对象之间建立关系,该对象链接到
    用户
    ,而不是直接链接(除非您开始遇到性能问题…)。将
    purchase
    作为事件记录“用户购买了这个和那个”使事情更容易处理。

    谢谢!非常有帮助!总和聚合功能是否没有严重的性能损失?假设每个聚合不再有20个项目?这是Django希望您这样做的方式,并且将由Django SQL生成来处理,因此我怀疑是否有一种方法可以更快地完成此操作,而不需要进行大量额外的工作来实现(如果有的话)。对于20个项目,您当然可以。除非您的网站上同时有数千个项目和数百个用户,否则性能问题最小@nunoth这是@vic解决方案的一个很好的补充,尽管如果您正在寻找性能,制作一个真实的atrtibut模型和一个填充它的信号将产生更好的结果。@e-satis有价值的评论+回答,+1ed。我喜欢这个想法,但我担心这会导致django对数据库进行两次查询,而不是一次查询。假设我正在将注释包列表从视图传递到模板,这一切都将在一个查询中完成。但是,如果我发送所有包并在tempelte call my model函数中调用,则可能会导致查询被拆分。我错了吗?还有,为什么我需要@property decorator?@Nuno_147
    @property
    为了优雅起见,这样您就可以从代码中访问它,而不仅仅是从模板中访问它。不确定总的DB点击数,取决于您将如何使用它。如果您有性能问题,请使用,但请记住,过早优化是有害的。我来自内核开发,所以我会关注性能。从来没有听说过早产是邪恶的:)也许我应该接受:)这只是我正在尝试做的事情的一个例子。这些都不是真正的模型。我只是想告诉你我在做什么。购买的模型实际上并不存在。