是否有一种方法可以在 过滤的相关模型字段 上执行注记总和,而在所有相关结果都被过滤掉后不返回None?
例如,对于下面的模型,我希望获得年度和每月的捐赠金额,但不包括未成功捐赠或已退款的捐赠。
我开始使用Case / When来避免没有捐赠的用户收到None而不是0的问题。但是我仍然需要排除不成功和已退还的捐款。
阅读Django's docs时,我发现您可以设置一个 自定义_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)
managers.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()