Мне нужно загрузить всю статистику по одному для каждой учетной записи пользователя.
Я использовал annotate () для соединения и вычисления полей других связанных моделей, но одно из полей, при добавлении, уничтожает все типы и умножает целое число на 10 в предыдущих полях в наборе запросов.
У меня есть 3 модели: AdvertisingAccount, Campaign, UserProfile.Я пробовал приводить для всех полей, но это не изменило картинку:
Мне нужно, чтобы целые числа были целыми числами, а десятичные дроби были десятичными с двумя десятичными знаками (как установлено в моделях).
ожидается:
ads_direct
313
303
31.12
2165.18
но получено:
ads_direct
3443
3333
342.320000000000
8441.80000000000
код в представлениях: (мне нужно, чтобы эти поля были вычислены)
accounts = user.userprofile.advertising_accounts.annotate(
clicks=Cast(Sum('campaigns__clicks', filter = Q(campaigns__userprofile = userprofile)), IntegerField()),
views=Cast(Sum('campaigns__views', filter = Q(campaigns__userprofile = userprofile)),IntegerField()),
ad_spent=Cast(Sum('campaigns__ad_spent', filter = Q(campaigns__userprofile = userprofile)),DecimalField(decimal_places=2)),
money_left = Sum('budgetings__deposited', filter = Q(budgetings__userprofile = userprofile)) - (Sum('campaigns__ad_spent', filter = Q(campaigns__userprofile = userprofile))),
)
Примечание Если я закомментирую money_left
, все аннотации вычисляются и отображаются в порядке (кроме десятичного знака: оно занимает12 мест вместо 2).
Я пробовал это, но это не изменило ситуацию:
accounts = user.userprofile.advertising_accounts.annotate(
clicks=Cast(Sum('campaigns__clicks', filter = Q(campaigns__userprofile = userprofile)), IntegerField()),
views=Cast(Sum('campaigns__views', filter = Q(campaigns__userprofile = userprofile)),IntegerField()),
ad_spent=Cast(Sum('campaigns__ad_spent', filter = Q(campaigns__userprofile = userprofile)),DecimalField(decimal_places=2)),
money_left = Cast((Sum('budgetings__deposited', filter = Q(budgetings__userprofile = userprofile)) - (Sum('campaigns__ad_spent', filter = Q(campaigns__userprofile = userprofile)))),DecimalField(decimal_places=2)),
)
шаблон
{% for i in accounts %}
{{i.foreign_system_name}}<p></p>
{{i.clicks}}<p></p>
{{i.views}}<p></p>
{{i.ad_spent}}<p></p>
{{i.money_left}}<p></p>
<p></p>
{% endfor %}
модели:
1
from django.db import models
from payments.models import Trade
# from users.models import UserProfile
# Create your models here.
class AdvertisingAccount(models.Model):
balance = models.DecimalField(max_digits=12, decimal_places=2, default=0, blank=True, null=True)
# eg yandex_direct or google_adwords
foreign_system_name = models.CharField(max_length=30, blank=True, default=None)
foreign_system_id = models.IntegerField(default=None, blank=True, null=True)
def __str__(self):
return self.foreign_system_name + '--' + str(self.foreign_system_id)
class Campaign(models.Model):
userprofile = models.ForeignKey('users.UserProfile', on_delete=models.PROTECT, related_name='campaigns')
# needs to open access to audience
trade = models.ForeignKey('payments.Trade', on_delete=models.PROTECT, related_name='campaigns')
ad_account = models.ForeignKey('AdvertisingAccount', on_delete=models.PROTECT, related_name='campaigns')
views = models.IntegerField(default=0, blank=True, null=True)
clicks = models.IntegerField(default=0, blank=True, null=True)
ad_spent = models.DecimalField(max_digits=12, decimal_places=2, default=0, blank=True, null=True)
def __str__(self):
return str(self.userprofile) + '--' + str(self.ad_account.foreign_system_name) + '--' + str(self.trade.ad_budget)
2
class AdAccountsBudgeting(models.Model):
userprofile = models.ForeignKey(UserProfile, on_delete=models.PROTECT)
ad_account = models.ForeignKey('advertiser.AdvertisingAccount', on_delete=models.PROTECT, related_name='budgetings')
deposited = models.DecimalField(max_digits=12, decimal_places=2, default=0, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.userprofile) + '--' + str(self.ad_account) + '--' + str(self.deposited)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.PROTECT)
role = models.CharField(max_length=15, default=None)
balance = models.DecimalField(max_digits=12, decimal_places=2, default=0, blank=True, null=True)
deposits = models.DecimalField(max_digits=12, decimal_places=2, default=0, blank=True, null=True)
advertising_accounts = models.ManyToManyField('advertiser.AdvertisingAccount', through='AdAccountsRelations', related_name='userprofiles' )
advertising_accounts_deposited = models.ManyToManyField('advertiser.AdvertisingAccount', through='AdAccountsBudgeting')
def __str__(self):
return self.user.username
Что может пойти не так при аннотировании?Что я должен сделать, чтобы соответствовать ожидаемому поведению?