使用 OuterRef 和 Sum 注释子查询的查询集
Queryset with annotate Subquery with OuterRef and Sum
我正在尝试 return 子查询中另一个模型的字段总和。
我的主要查询集return是公司类型的所有用户。我必须 return 通过从 CreditOrder 中获取数据并对 credit_used 字段求和来计算所使用的积分总数。
我正在使用来自 django-modelcluster
的 ClusterableModel 和 ParentalKey
我的CreditOrder
模特
class CreditOrder(ClusterableModel):
credit = ParentalKey(
Credit, on_delete=models.CASCADE, related_name="credit_order"
)
order = ParentalKey(Order, on_delete=models.CASCADE, related_name="credit_order")
credit_used = models.DecimalField(
max_digits=12, decimal_places=2, null=True, blank=True
)
我的User
模特
class User(AbstractUser, ClusterableModel):
username = models.CharField(max_length=40, null=True, blank=True)
user_type = models.CharField(max_length=20, choices=TIPO_UTENTE, default="dipendente")
我的查询集使用 class 模型用户
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.filter(user_type='company')
credits_used_subquery = Subquery(CreditOrder.objects.filter(credit__font__company__id=OuterRef('id')).order_by()
.values('credit_used').annotate(credit_used_sum=Sum('credit_used'))
.values('credit_used_sum'), output_field=DecimalField())
qs = qs.annotate(
_credits_used_sum=credits_used_subquery
)
return qs
但是这个错误 return 给我:
django.db.utils.ProgrammingError: more than one row returned by a subquery used as an expression
如果您只需要将公司使用的所有积分相加,您可以这样做:
qs.annotate(_credits_used_sum=Sum('font__credit__credit_used'))
在没有看到 CreditOrder 和 User 之间的所有模型的情况下,很难准确判断出哪里出了问题。看起来 Credit 模型链接到 Font 并且 Font 可能有一个名为 Company 的属性,它是 User 模型的外键?
在任何情况下,您的第一个 values
调用都有错误的参数,您需要根据您在外部引用中链接到的基本相同的内容进行分组。所以我建议
.values('credit__font__company__id')
在第一次调用值。并保持对值的注释和第二次调用相同。
另一个答案建议用连接而不是子查询来求和,如果你喜欢它的简单性 api,但你仍然想使用子查询,你可以使用 django-sql-utils包裹。在你之后[=13=]
from sql_util.utils import SubquerySum
qs.annotate(_credits_used_sum=SubquerySum('font_credit_credit_used')
我用这个 class 解决了我的问题:
class SubquerySum(Subquery):
template = "(SELECT COALESCE(SUM(%(field)s), %(zero_value)s) FROM (%(subquery)s) _sum)"
def as_sql(self, compiler, connection, template=None, **extra_context):
if 'field' not in extra_context and 'field' not in self.extra:
if len(self.queryset._fields) > 1:
raise FieldError('You must provide the field name, or have a single column')
extra_context['field'] = self.queryset._fields[0]
if 'zero_value' not in extra_context and 'zero_value' not in self.extra:
extra_context['zero_value'] = 0
return super().as_sql(compiler, connection, template=template, **extra_context)
和
def get_queryset(self, request):
credit_query=CreditOrder.objects.filter(credit__font__company__id=OuterRef('id')).order_by()
.values('credit_used')
qs = super().get_queryset(request)
qs = qs.filter(user_type='company')
qs = qs.annotate(
_credits_used_sum=SubquerySum(credit_query, zero_value=0, field='credit_used')
)
return qs
我正在尝试 return 子查询中另一个模型的字段总和。
我的主要查询集return是公司类型的所有用户。我必须 return 通过从 CreditOrder 中获取数据并对 credit_used 字段求和来计算所使用的积分总数。
我正在使用来自 django-modelcluster
的 ClusterableModel 和 ParentalKey我的CreditOrder
模特
class CreditOrder(ClusterableModel):
credit = ParentalKey(
Credit, on_delete=models.CASCADE, related_name="credit_order"
)
order = ParentalKey(Order, on_delete=models.CASCADE, related_name="credit_order")
credit_used = models.DecimalField(
max_digits=12, decimal_places=2, null=True, blank=True
)
我的User
模特
class User(AbstractUser, ClusterableModel):
username = models.CharField(max_length=40, null=True, blank=True)
user_type = models.CharField(max_length=20, choices=TIPO_UTENTE, default="dipendente")
我的查询集使用 class 模型用户
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.filter(user_type='company')
credits_used_subquery = Subquery(CreditOrder.objects.filter(credit__font__company__id=OuterRef('id')).order_by()
.values('credit_used').annotate(credit_used_sum=Sum('credit_used'))
.values('credit_used_sum'), output_field=DecimalField())
qs = qs.annotate(
_credits_used_sum=credits_used_subquery
)
return qs
但是这个错误 return 给我:
django.db.utils.ProgrammingError: more than one row returned by a subquery used as an expression
如果您只需要将公司使用的所有积分相加,您可以这样做:
qs.annotate(_credits_used_sum=Sum('font__credit__credit_used'))
在没有看到 CreditOrder 和 User 之间的所有模型的情况下,很难准确判断出哪里出了问题。看起来 Credit 模型链接到 Font 并且 Font 可能有一个名为 Company 的属性,它是 User 模型的外键?
在任何情况下,您的第一个 values
调用都有错误的参数,您需要根据您在外部引用中链接到的基本相同的内容进行分组。所以我建议
.values('credit__font__company__id')
在第一次调用值。并保持对值的注释和第二次调用相同。
另一个答案建议用连接而不是子查询来求和,如果你喜欢它的简单性 api,但你仍然想使用子查询,你可以使用 django-sql-utils包裹。在你之后[=13=]
from sql_util.utils import SubquerySum
qs.annotate(_credits_used_sum=SubquerySum('font_credit_credit_used')
我用这个 class 解决了我的问题:
class SubquerySum(Subquery):
template = "(SELECT COALESCE(SUM(%(field)s), %(zero_value)s) FROM (%(subquery)s) _sum)"
def as_sql(self, compiler, connection, template=None, **extra_context):
if 'field' not in extra_context and 'field' not in self.extra:
if len(self.queryset._fields) > 1:
raise FieldError('You must provide the field name, or have a single column')
extra_context['field'] = self.queryset._fields[0]
if 'zero_value' not in extra_context and 'zero_value' not in self.extra:
extra_context['zero_value'] = 0
return super().as_sql(compiler, connection, template=template, **extra_context)
和
def get_queryset(self, request):
credit_query=CreditOrder.objects.filter(credit__font__company__id=OuterRef('id')).order_by()
.values('credit_used')
qs = super().get_queryset(request)
qs = qs.filter(user_type='company')
qs = qs.annotate(
_credits_used_sum=SubquerySum(credit_query, zero_value=0, field='credit_used')
)
return qs