I am trying to add sum for credits that are taxable my models.py. If I calculate the balance without the taxable_credits it works. The minute I add the taxable_credits into the mix I get the error.
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)
My test is as follows:
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'))]
"""
When run the test I get the follow error traceback
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.
I have tried adding output_field to Subquery, which makes no sense to me, but get another error.
Guidance would be appreciated