我正在使用 Django 2.x 。
我有两个模型
class AmountGiven(models.Model):
contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
amount = models.FloatField(help_text='Amount given to the contact')
interest_rate = models.FloatField(blank=True, default=None, null=True)
given_date = models.DateField(default=timezone.now)
total_due = models.FloatField(blank=True, default=0.0, editable=False)
class AmountReturned(models.Model):
amount_given = models.ForeignKey(AmountGiven, on_delete=models.CASCADE, blank=True)
amount = models.FloatField()
return_date = models.DateField(default=date.today)
用例
现在,我想为某个特定联系人获得total_due
的金额。其中包括
total_payable = total_given + interest
total_due = total_payable - total_returned
要计算total_due
和interest
,我在 AmountGiven 模型中定义了几种属性方法。
@property
def interest_to_pay(self):
if self.interest_rate:
simple_interest_amount = ...
return simple_interest_amount
return 0
@property
def total_payable(self):
return self.amount + self.interest_to_pay
@property
def amount_due(self):
total_due = self.total_payable - self.total_returned
self.total_due = total_due
self.save()
return total_due
@property
def total_returned(self):
returned_amount = self.amountreturned_set.aggregate(total_returned=Sum('amount'))['total_returned']
if not returned_amount:
returned_amount = 0
return returned_amount
在联系人模型中,有一种属性方法来获取联系人的应付款总额。
@property
def amount_due(self):
total_due = 0
for due in self.amountgiven_set.all():
total_due += due.amount_due
return total_due
查询
ContactSerializer
class ContactMinSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = (
'id', 'first_name', 'amount_due', 'created', 'modified'
)
由于amount_due
中使用了ContactSerializer
属性,因此每次调用联系人时都会调用amount_due
属性,从而导致嵌套的数据库查询。
如何在应用程序中优化上述方案,以减少获取联系人或联系人列表时的数据库查询?特别是两个属性 amount_due 和 total_returned 。
每次调用amount_due()都会更新表中的 total_due 字段。
编辑2
class ContactViewSet(LoggingMixin, viewsets.ModelViewSet):
serializer_class = ContactMinSerializer
def get_queryset(self):
return Contact.objects.filter(user=self.request.user).annotate(
total_due=Sum(
F('amountgiven_set__total_payable')
- F('amountgiven_set__total_returned')
)
).order_by('first_name')
答案 0 :(得分:0)
You're looking for annotations.
您的视图集应如下定义查询集:
def create_foo(value):
return Foo(value)
def concatenate(lhs, rhs):
return list(lhs) + list(rhs)
concatenate(concatenate(create_foo(1), create_foo(2)), create_foo(3))
然后在序列化程序上定义一个MethodSerializer字段以解决该问题。
from django.db.models import F, Sum
Contact.objects.annotate(
total_due=Sum(
F('amountgiven_set__total_payable')
- F('amountgiven_set__total_returned')
)
)