【问题标题】:Sum values from child models using nested Subquery and annotaions in Django Viewset使用 Django Viewset 中的嵌套子查询和注释对子模型的值求和
【发布时间】:2021-07-24 08:22:39
【问题描述】:

我正在尝试计算食谱的总价格。为了优化数据库查询,我尝试使用 Django 的 ORM 功能来执行最少的请求。

我的models.py是这样的:

class BaseRecipe(models.Model):
    title = models.CharField(_('Base recipe title'), max_length=255, 
    user = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name='user_base_recipes')

    class Meta:
        ordering = ['title']


    def __str__(self):
        return self.title


class IngredientBaseRecipe(models.Model):
    base_recipe = models.ForeignKey(BaseRecipe, on_delete=models.CASCADE, related_name='ingredients')
    name = models.CharField(_('Name'), max_length=255)
    products = models.ManyToManyField(Product)
    quantity = models.FloatField(_('Quantity'), default=0.0)

    class Meta:
        ordering = ['-id']

    def __str__(self):
        return self.name


class Product(models.Model):
    name = models.CharField(_('Name'), max_length=255, help_text=_('Product name'))
    price = models.FloatField(_('Sale price'), default=0)

    class Meta:
        ordering = ['name', ]
        indexes = [models.Index(fields=['name',]), ]

然后在我的 Viewset 中,我试图获取 BaseRecipes 查询集,其中包含一个显示成分价格总和的带注释字段。我得到了获取原料价格的目的,但我试图在 BaseRecipe 查询集中对它们求和:

min_price = (
    Product.objects.filter(name=OuterRef('name'))
        .annotate(min_price=Min('price'))
        .values('min_price')
)

ingredients_price = (
    IngredientBaseRecipe.objects
        .filter(base_recipe=OuterRef('id'))
        .annotate(price=Subquery(min_price))
        .order_by()
        .annotate(total=Sum(F('price') * F('quantity')))
        .values('total')
)

queryset = BaseRecipe.objects.filter(user=self.request.user) \
    .annotate(cost=Sum(ingredients_price))
return queryset

非常感谢您的帮助!

【问题讨论】:

    标签: django django-models django-orm


    【解决方案1】:

    最后我通过在子查询中求和得到了一个解决方案:

    min_price = (
        Product.objects.filter(name=OuterRef('name'))
            .annotate(min_price=Min('price'))
            .order_by()
            .values('min_price')
    )
    ingredients_price = (
        IngredientBaseRecipe.objects
            .filter(base_recipe__pk=OuterRef('id'))
            .prefetch_related('products')
            .select_related('base_recipe')
            .annotate(price=Subquery(min_unit_price))
            .values('base_recipe__pk')
            .order_by()
            .annotate(total=ExpressionWrapper(Sum(F('price') * F('quantity')), output_field=FloatField()))
            .values('total')
    )
    queryset = BaseRecipe.objects.filter(user=self.request.user) \
        .prefetch_related('ingredients', 'ingredients__products') \
        .annotate(cost=Subquery(ingredients_price))
    return queryset
    

    【讨论】:

      猜你喜欢
      • 2018-04-16
      • 1970-01-01
      • 1970-01-01
      • 2017-11-08
      • 2020-01-26
      • 2021-04-22
      • 2019-01-05
      • 2021-09-17
      • 1970-01-01
      相关资源
      最近更新 更多