Python Django子查询表达式包含混合类型。您必须设置输出字段
我正在尝试为我的models.py应税的信用证添加金额。如果我计算的余额没有应税的大学学分,它的工作。当我把应税的信用卡加入到组合中时,我得到了错误Python Django子查询表达式包含混合类型。您必须设置输出字段,python,django,subquery,django-annotate,Python,Django,Subquery,Django Annotate,我正在尝试为我的models.py应税的信用证添加金额。如果我计算的余额没有应税的大学学分,它的工作。当我把应税的信用卡加入到组合中时,我得到了错误 class Account(models.Model): name = models.CharField(max_length=32) class Debit(models.Model): account = models.ForeignKey(Account, related_name='debits', on_delete=
class Account(models.Model):
name = models.CharField(max_length=32)
class Debit(models.Model):
account = models.ForeignKey(Account, related_name='debits', on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=12, decimal_places=2)
class Credit(models.Model):
account = models.ForeignKey(Account, related_name='credits', on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=12, decimal_places=2)
taxable = models.BooleanField(default=False)
我的测试如下:
lass TestAccount(TestCase):
# https://mixedquantum.blogspot.com/2017/08/django-tips-3-subquery-expressions.html
def setUp(self) -> None:
self.accounts = dict()
self.accounts['fox'] = Account.objects.create(name='FOX')
self.accounts['dog'] = Account.objects.create(name='DOG')
self.accounts['snake'] = Account.objects.create(name='SNAKE')
"""
# Credits
+----------------+-----------------+-----------------+
| account_name | credit_amount | taxable |
|----------------+-----------------|-----------------+
| FOX | 100.0 | False |
| SNAKE | 50.0 | False |
| SNAKE | 20.0 | False |
| DOG | 300.0 | False |
| DOG | 100.0 | True |
+----------------+-----------------+-----------------+
"""
Credit.objects.create(account=self.accounts['fox'], amount=Decimal('100.0'))
Credit.objects.create(account=self.accounts['snake'], amount=Decimal('50.0'))
Credit.objects.create(account=self.accounts['snake'], amount=Decimal('20.0'))
Credit.objects.create(account=self.accounts['dog'], amount=Decimal('300.0'))
Credit.objects.create(account=self.accounts['dog'], amount=Decimal('100.0'), taxable=True)
"""
# Debits
+----------------+----------------+
| account_name | dedit_amount |
|----------------+----------------|
| FOX | 40.0 |
| SNAKE | 30.0 |
| DOG | 12.0 |
| DOG | 23.0 |
+----------------+----------------+
"""
Debit.objects.create(account=self.accounts['fox'], amount=Decimal('40.0'))
Debit.objects.create(account=self.accounts['snake'], amount=Decimal('30.0'))
Debit.objects.create(account=self.accounts['dog'], amount=Decimal('12.0'))
Debit.objects.create(account=self.accounts['dog'], amount=Decimal('23.0'))
def test_sum(self):
credits = Credit.objects.filter(
account=OuterRef('pk')).values('account_id').annotate(sum_credits=Sum('amount'))
taxable_credits = Credit.objects.filter(
account=OuterRef('pk'), taxable=True).values('account_id').annotate(sum_taxable_credits=Sum('amount'))
debits = Debit.objects.filter(
account=OuterRef('pk')).values('account_id').annotate(sum_debits=Sum('amount'))
balances = Account.objects.annotate(
credit_sum=Subquery(credits.values('sum_credits')),
taxable_credit_sum=Subquery(taxable_credits.values('sum_taxable_credits')),
debit_sum=Subquery(debits.values('sum_debits')),
balance= F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).values_list('name', 'balance') # , 'taxable_credit_sum')
self.assertEqual(balances[0], ('FOX', Decimal('60.0')))
self.assertEqual(balances[2], ('SNAKE', Decimal('40.0')))
self.assertEqual(balances[1], ('DOG', Decimal('365.0')))
"""
[('FOX', Decimal('60.00')),
('SNAKE', Decimal('40.00')),
('DOG', Decimal('265.00'))]
"""
当运行测试时,我得到以下错误回溯
Error
Traceback (most recent call last):
File "/opt/project/alpha_clinic/banking/tests/tests_models.py", line 65, in test_sum
self.assertEqual(balances[0], ('FOX', Decimal('60.0')))
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 308, in __getitem__
qs._fetch_all()
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 1242, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 144, in __iter__
return compiler.results_iter(tuple_expected=True, chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1085, in results_iter
results = self.execute_sql(MULTI, chunked_fetch=chunked_fetch, chunk_size=chunk_size)
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1120, in execute_sql
sql, params = self.as_sql()
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 474, in as_sql
extra_select, order_by, group_by = self.pre_sql_setup()
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 54, in pre_sql_setup
self.setup_query()
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 45, in setup_query
self.select, self.klass_info, self.annotation_col_map = self.get_select()
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 254, in get_select
sql, params = self.compile(col, select_format=True)
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 407, in compile
return node.output_field.select_format(self, sql, params)
File "/usr/local/lib/python3.6/site-packages/django/utils/functional.py", line 80, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 258, in output_field
output_field = self._resolve_output_field()
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 290, in _resolve_output_field
sources_iter = (source for source in self.get_source_fields() if source is not None)
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 344, in get_source_fields
return [e._output_field_or_none for e in self.get_source_expressions()]
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 344, in <listcomp>
return [e._output_field_or_none for e in self.get_source_expressions()]
File "/usr/local/lib/python3.6/site-packages/django/utils/functional.py", line 80, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 271, in _output_field_or_none
return self.output_field
File "/usr/local/lib/python3.6/site-packages/django/utils/functional.py", line 80, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 258, in output_field
output_field = self._resolve_output_field()
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 1010, in _resolve_output_field
return super()._resolve_output_field()
File "/usr/local/lib/python3.6/site-packages/django/db/models/expressions.py", line 293, in _resolve_output_field
raise FieldError('Expression contains mixed types. You must set output_field.')
django.core.exceptions.FieldError: Expression contains mixed types. You must set output_field.
错误
回溯(最近一次呼叫最后一次):
文件“/opt/project/alpha_clinic/banking/tests/tests_models.py”,第65行,test_sum中
self.assertEqual(余额[0],('FOX',十进制('60.0'))
文件“/usr/local/lib/python3.6/site packages/django/db/models/query.py”,第308行,在__
Q._fetch_all()
文件“/usr/local/lib/python3.6/site packages/django/db/models/query.py”,第1242行,在“fetch\u all”中
self.\u result\u cache=list(self.\u iterable\u class(self))
文件“/usr/local/lib/python3.6/site packages/django/db/models/query.py”,第144行,在__
返回compiler.results\u iter(tuple\u expected=True,chunked\u fetch=self.chunked\u fetch,chunk\u size=self.chunk\u size)
文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,结果文件第1085行
results=self.execute\u sql(MULTI,chunked\u fetch=chunked\u fetch,chunk\u size=chunk\u size)
文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,第1120行,在execute\u sql中
sql,params=self.as_sql()
as_sql中的文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,第474行
extra\u select、order\u by、group\u by=self.pre\u sql\u setup()
文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,第54行,在预sql设置中
self.setup\u查询()
文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,第45行,在setup\u查询中
self.select、self.klass\u info、self.annotation\u col\u map=self.get\u select()
文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,第254行,在get_select中
sql,params=self.compile(col,select\u format=True)
文件“/usr/local/lib/python3.6/site packages/django/db/models/sql/compiler.py”,第407行,在compile中
返回节点。输出\字段。选择\格式(self、sql、params)
文件“/usr/local/lib/python3.6/site packages/django/utils/functional.py”,第80行,在__
res=instance.\uuuu dict\uuuu[self.name]=self.func(实例)
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第258行,在输出字段中
输出\字段=自身。\解析\输出\字段()
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第290行,在“解析输出”字段中
sources\u iter=(如果source不是None,则在self.get\u source\u fields()中为source指定源)
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第344行,在get\u source\u字段中
在self.get\u source\u expressions()中为e返回[e.\u output\u field\u或\u none]
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第344行,在
在self.get\u source\u expressions()中为e返回[e.\u output\u field\u或\u none]
文件“/usr/local/lib/python3.6/site packages/django/utils/functional.py”,第80行,在__
res=instance.\uuuu dict\uuuu[self.name]=self.func(实例)
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第271行,在输出字段或无字段中
返回self.output_字段
文件“/usr/local/lib/python3.6/site packages/django/utils/functional.py”,第80行,在__
res=instance.\uuuu dict\uuuu[self.name]=self.func(实例)
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第258行,在输出字段中
输出\字段=自身。\解析\输出\字段()
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第1010行,在“解析输出”字段中
返回super()
文件“/usr/local/lib/python3.6/site packages/django/db/models/expressions.py”,第293行,在“解析输出”字段中
raise FIELDVERROR('表达式包含混合类型。必须设置输出\字段')
django.core.exceptions.FieldError:表达式包含混合类型。您必须设置输出字段。
我曾尝试将output_字段添加到子查询,这对我来说毫无意义,但又出现了另一个错误
请提供指导您可以使用其他聚合功能创建这些注释,而无需使用子查询。此答案中使用的所有函数都是这样导入的
from django.db.models import Sum, Case, When, F, Value
balances = Account.objects.annotate(
credit_sum=Sum('credits__amount', distinct=F('credits__id')),
debit_sum=Sum('debits__amount', distinct=F('debits__id')),
taxable_credit_sum=Sum(Case(
When(credits__taxable=True, then=F('credits__amount')),
default=Value(0),
output_field=models.DecimalField()
), distinct=F('credits__id'))
).annotate(
balance=F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).order_by('id').values_list('name', 'balance')
要注释相关记录的总和,可以执行以下操作:
Account.objects.annotate(
credit_sum=Sum('credits__amount')
).values('name', 'credit_sum')
# <QuerySet [{'name': 'FOX', 'credit_sum': Decimal('100.00')}, {'name': 'DOG', 'credit_sum': Decimal('400.00')}, {'name': 'SNAKE', 'credit_sum': Decimal('70.00')}]>
要有条件地对行进行求和或计数,您可以使用应纳税\u信用\u sum
注释
from django.db.models import Sum, Case, When, F, Value
balances = Account.objects.annotate(
credit_sum=Sum('credits__amount', distinct=F('credits__id')),
debit_sum=Sum('debits__amount', distinct=F('debits__id')),
taxable_credit_sum=Sum(Case(
When(credits__taxable=True, then=F('credits__amount')),
default=Value(0),
output_field=models.DecimalField()
), distinct=F('credits__id'))
).annotate(
balance=F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).order_by('id').values_list('name', 'balance')
现在您应该有了所需的查询
您不需要同时计算抵免额和非应税抵免额
由于您只是从另一个中减去一个,因此您只需为此创建一个注释,将所有不应纳税的信用额相加即可
balances = Account.objects.annotate(
debit_sum=Sum('debits__amount', distinct=F('debits__id')),
non_taxable_credit_sum=Sum(Case(
When(credits__taxable=False, then=F('credits__amount')),
default=Value(0),
output_field=models.DecimalField()
), distinct=F('credits__id'))
).annotate(
balance=F('non_taxable_credit_sum') - F('debit_sum')
).order_by('id').values_list('name', 'balance')
您可以使用其他聚合函数创建这些注释,而无需使用
子查询
。此答案中使用的所有函数都是这样导入的
from django.db.models import Sum, Case, When, F, Value
balances = Account.objects.annotate(
credit_sum=Sum('credits__amount', distinct=F('credits__id')),
debit_sum=Sum('debits__amount', distinct=F('debits__id')),
taxable_credit_sum=Sum(Case(
When(credits__taxable=True, then=F('credits__amount')),
default=Value(0),
output_field=models.DecimalField()
), distinct=F('credits__id'))
).annotate(
balance=F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).order_by('id').values_list('name', 'balance')
要注释相关记录的总和,可以执行以下操作:
Account.objects.annotate(
credit_sum=Sum('credits__amount')
).values('name', 'credit_sum')
# <QuerySet [{'name': 'FOX', 'credit_sum': Decimal('100.00')}, {'name': 'DOG', 'credit_sum': Decimal('400.00')}, {'name': 'SNAKE', 'credit_sum': Decimal('70.00')}]>
要有条件地对行进行求和或计数,您可以使用应纳税\u信用\u sum
注释
from django.db.models import Sum, Case, When, F, Value
balances = Account.objects.annotate(
credit_sum=Sum('credits__amount', distinct=F('credits__id')),
debit_sum=Sum('debits__amount', distinct=F('debits__id')),
taxable_credit_sum=Sum(Case(
When(credits__taxable=True, then=F('credits__amount')),
default=Value(0),
output_field=models.DecimalField()
), distinct=F('credits__id'))
).annotate(
balance=F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).order_by('id').values_list('name', 'balance')
现在您应该有了所需的查询
您不需要同时计算抵免额和非应税抵免额
由于您只是从另一个中减去一个,因此您只需为此创建一个注释,将所有不应纳税的信用额相加即可
balances = Account.objects.annotate(
debit_sum=Sum('debits__amount', distinct=F('debits__id')),
non_taxable_credit_sum=Sum(Case(
When(credits__taxable=False, then=F('credits__amount')),
default=Value(0),
output_field=models.DecimalField()
), distinct=F('credits__id'))
).annotate(
balance=F('non_taxable_credit_sum') - F('debit_sum')
).order_by('id').values_list('name', 'balance')
您可以尝试以下操作:
credits = Credit.objects.filter(account=OuterRef('pk')).values('account_id').annotate(sum_credits=Sum('amount'))
taxable_credits = Credit.objects.filter(account=OuterRef('pk'), taxable=True).values('account_id').annotate(sum_taxable_credits=Sum('amount'))
debits = Debit.objects.filter(account=OuterRef('pk')).values('account_id').annotate(sum_debits=Sum('amount'))
balances = Account.objects.annotate(
credit_sum=Case(When(Exists(credits), then=Subquery(credits.values('sum_credits'))), default=Value(0)),
taxable_credit_sum=Case(When(Exists(taxable_credits), then=Subquery(taxable_credits.values('sum_taxable_credits'))), default=Value(0)),
debit_sum=Case(When(Exists(debits), then=Subquery(debits.values('sum_debits'))), default=Value(0)),
balance=F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).values_list('name', 'balance') # , 'taxable_credit_sum')
self.assertEqual(balances[0], ('FOX', Decimal('60.0')))
self.assertEqual(balances[2], ('SNAKE', Decimal('40.0')))
self.assertEqual(balances[1], ('DOG', Decimal('265.0')))
您可以尝试以下操作:
credits = Credit.objects.filter(account=OuterRef('pk')).values('account_id').annotate(sum_credits=Sum('amount'))
taxable_credits = Credit.objects.filter(account=OuterRef('pk'), taxable=True).values('account_id').annotate(sum_taxable_credits=Sum('amount'))
debits = Debit.objects.filter(account=OuterRef('pk')).values('account_id').annotate(sum_debits=Sum('amount'))
balances = Account.objects.annotate(
credit_sum=Case(When(Exists(credits), then=Subquery(credits.values('sum_credits'))), default=Value(0)),
taxable_credit_sum=Case(When(Exists(taxable_credits), then=Subquery(taxable_credits.values('sum_taxable_credits'))), default=Value(0)),
debit_sum=Case(When(Exists(debits), then=Subquery(debits.values('sum_debits'))), default=Value(0)),
balance=F('credit_sum') - F('debit_sum') - F('taxable_credit_sum')
).values_list('name', 'balance') # , 'taxable_credit_sum')
self.assertEqual(balances[0], ('FOX', Decimal('60.0')))
self.assertEqual(balances[2], ('SNAKE', Decimal('40.0')))
self.assertEqual(balances[1], ('DOG', Decimal('265.0')))
如果您可以在一个注释中计算,您是否关心创建两个注释
贷记金额
和应纳税贷记金额
?它们会在其他地方使用吗?如果只使用一种模式(收费
或其他什么)来取代信用
和借记
模式会更容易吗?查询要容易得多你关心cre吗