Есть ли способ выполнить сумму аннотации для отфильтрованных связанных полей модели без возврата Нет, когда все связанные результаты отфильтрованы?
Например,в приведенных ниже моделях я хотел бы иметь годовые и ежемесячные суммы пожертвований, но исключая пожертвования, которые не были успешными или были возвращены.
Я начал использовать Case / When, чтобы избежать проблемы получения None, а не 0 дляпользователи без пожертвований.Но мне все еще нужно исключить неудачные и возвращенные пожертвования.
Чтение Документы Джанго , я обнаружил, что вы можете установить пользовательский _base_manager , но затем "Менеджеры баз не используются при запросах к связанным моделям" .
Есть ли другой подход, который я мог бы использовать?
models.py
class Profile(Model):
user = OneToOneField(
User,
on_delete=CASCADE,
related_name='profile'
)
has_donor_access = BooleanField(
default=False
)
...
objects = Manager()
account_objects = AccountManager()
def __str__(self):
return "{0} :: {1}".format(
self.user.get_full_name(), self.user.get_username())
class Donation(Model):
user = ForeignKey(
User,
blank=True,
null=True,
on_delete=SET_NULL,
related_name='donations',
verbose_name=_('donor')
)
creation_date = DateTimeField(
auto_now_add=True
)
amount = DecimalField(
decimal_places=2,
max_digits=9
)
is_success = NullBooleanField(
default=True
)
is_refunded = NullBooleanField(
default=False
)
...
def __str__(self):
user_profile = self.user.profile if self.user else "Anonymous"
return "{0} :: ${1} :: {2}".format(
user_profile, self.amount, self.creation_date)
Manager.py
class AccountQuerySet(QuerySet):
def with_donation_stats(self):
a_month_ago = now() - relativedelta(months=1)
a_year_ago = now() - relativedelta(years=1)
return self.annotate(
_yearly_donations_sum=Case(
When(
Q(user__donations__isnull=False),
then=Sum(
'user__donations__amount',
filter=(
Q(user__donations__is_success=True)
& Q(user__donations__is_refunded=False)
& Q(user__donations__creation_date__gte=a_year_ago)
)
)
),
default=0,
output_field=PositiveIntegerField()
),
_monthly_donations_sum=Case(
When(
Q(user__donations__isnull=False),
then=Sum(
'user__donations__amount',
filter=(
Q(user__donations__is_success=True)
& Q(user__donations__is_refunded=False)
& Q(user__donations__creation_date__gte=a_month_ago)
)
)
),
default=0,
output_field=PositiveIntegerField()
)
)
)
class AccountManager(Manager):
def get_queryset(self):
return AccountQuerySet(
self.model,
using=self._db
)
def with_donation_stats(self):
return self.get_queryset().with_donation_stats()