Как добавить пару ключ-значение в набор запросов django - PullRequest
0 голосов
/ 11 июля 2019

Я хочу показать статистику по аккаунту по аккаунту в цикле шаблона.В списке диктов или наборов запросов.

У меня есть 3 модели: (1) AdvertisingAccount, (2) Campaign, UserProfile.Мне нужно суммировать () клики и просмотры кампаний, принадлежащих определенным рекламным аккаунтам по внешнему ключу.(AdvertisingAccount также принадлежит UserProfile)

Я пытаюсь получить, вычислить и добавить новое значение ключа к диктовкам набора запросов, но, похоже, я не могу сделать это в методе dict…

views.py

def ad_accounts(request):

    user = request.user
    accounts = user.userprofile.advertising_accounts.all()

    accounts = accounts.values()

    for d in accounts:
        d.update(('clicks', d.campaigns.all().aggregate(Sum('clicks')) )  for k,v in d.items())
        d.update(('views', d.campaigns.all().aggregate(Sum('views')) )  for k,v in d.items())

models.py


class AdvertisingAccount(models.Model):
    balance = models.DecimalField(max_digits=12, decimal_places=2, default=0, blank=True, null=True)
    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')
    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)

шаблон

{% for i in accounts %}
  {{i.clicks}}
  {{i.views}}
{% endfor %}

Iполучена ошибка: 'dict' object has no attribute 'campaigns'

Поскольку я не могу получить отфильтрованные данные из шаблонов, я пытаюсь создать собственный набор запросов или список запросов.Целый путь правильный?Как решить мою проблему?

1 Ответ

5 голосов
/ 11 июля 2019

Пожалуйста, делайте , а не , комментируйте вручную, вы можете просто использовать метод .annotate(..) Джанго [Django-doc] .Вы даже использовали генератор здесь, где он приведет к запросу много раз для одной Account модели.

from django.db.models import Sum

accounts = user.userprofile.advertising_accounts.annotate(
    <b>clicks=Sum('campaigns__clicks'),</b>
    <b>views=Sum('campaigns__views')</b>
)

Выше будет сгенерировано QuerySet из AdvertisingAccount s и с дополнительными атрибутами .clicks и .views.На самом деле ошибка полностью в том, что вы использовали не AdvertisingAccount s в первую очередь, а словари (которые происходят от .values(), и вы таким образом теряете контекст отношений).

Аннотациябудет выполняться в одном запросе, где Django сделает запрос, который выглядит следующим образом:

SELECT advertising_acount.*,
       SUM(campaign.clicks) AS clicks,
       SUM(campaign.views) AS views
FROM advertising_acount
LEFT OUTER JOIN campaign ON campaign.ad_account_id = advertising_acount.id
GROUP BY advertising_acount.id

Это более эффективно, чем агрегирование за AdvertisingAccount, так как тогда вы попадете в базу данных 2n + 1 раз здесь с n числом AdvertisingAcount с.

Поэтому обычно почти всегда лучше использовать экземпляр модели над словарем: модельКласс позволяет вам определять методы, свойства, он добавляет отношения и т. д. Он также содержит тип объекта (например, AdvertisingAccount), тогда как два словаря с одинаковыми ключами сами по себе не происходят из одних и тех же моделей.Словарь - это просто плоская структура, которая отображает имена полей в соответствующее значение базы данных.Таким образом, вы «теряете» много контекста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...