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()
我正试图以尽可能最好的性能实现两个功能:
我可以轻松地使用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点击数,取决于您将如何使用它。如果您有性能问题,请使用,但请记住,过早优化是有害的。我来自内核开发,所以我会关注性能。从来没有听说过早产是邪恶的:)也许我应该接受:)这只是我正在尝试做的事情的一个例子。这些都不是真正的模型。我只是想告诉你我在做什么。购买的模型实际上并不存在。