我有两个型号
class Model1(models.Model):
name = models.CharField()
和
class Model2(models.Model):
model1 = models.ForeignKey(Model1)
price = models.IntegerField()
如何在这两个模型之间进行简单连接?我希望Model1中的所有对象都具有Model2中与特定Model1对象相关的所有对象的价格总和。
我想这就像是
queryset = Model1.objects.annotate(model2_price=Sum(price)).values('name','model2_price')
答案 0 :(得分:0)
您已使用注释关闭了。只需在Sum()
中使用有效的查找字符串即可:
queryset = Model1.objects.annotate(model2_price=Sum('model1__price'))
for m in queryset:
print m.model2_price
编辑:
我忽略了ForeignKey
从Model2
到Model1
,但这绝对没有问题。在模型中,Django自动为所有OneToOneField
,ForeignKey
和ManyToManyField
添加反向关系。您可以将related_name
参数传递给其中每个字段以更改反向关系的属性名称,但默认情况下它将为<lowercase_modelname>_set
。所以你现在需要做的是:
queryset = Model1.objects.annotate(model2_price=Sum('model2_set__price'))
我通常建议明确定义相关名称并使用它来引用相关对象,以避免混淆属性名称,并可能为关系提供更具描述性的名称:
class Model2(models.Model):
model1 = models.ForeignKey(Model1, related_name='model2')
price = models.IntegerField()
queryset = Model1.objects.annotate(model2_price=Sum('model2__price'))
编辑2 : 查询的结果无法修改,注释不支持更复杂的查询。有几种方法可以解决这个问题,我最喜欢这个:
class Model1(models.Model):
name = models.CharField()
@property
def model2_total_price(self):
if not hasattr(self, '_model2_total_price'):
raise AttributeError("'%s' object has no attribute 'model2_total_price'" % self.__class__.__name__)
if self._model2_total_price:
return self._model2_total_price
return 0
queryset = Model1.objects.annotate(_model2_total_price=Sum('model2_set__price'))
for m in queryset:
print m.model2_total_price
这与您注释名为model2_total_price
的字段的行为完全相同,包括如果根本不使用注释则引发AttributeError
,而如果0
则仍然返回model2_set
1}}是空的。 @property
装饰器允许您使用实例方法,就像它是常规属性一样(尽管您无法在不提供额外的setter方法的情况下进行设置)。 _model2_total_price
中的起始下划线告诉其他开发者远离该属性,除非他们确切地知道他们正在做什么以及他们为什么要改变它(替换正确的私有属性)在其他语言中,没有强制执行 - 这是Pythonesque的做法。
您唯一需要确保的是始终为注释使用完全相同的属性名称:在此示例中为_model2_total_price
。