优化 django sql 查询

optimise django sql query

我正在使用 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_dueinterest,我在AmountGiven[=62]中定义了几个属性方法=] 模型.

@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

Contact 模型中,有一个 属性 方法来获取联系人的总应付金额。

@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_duetotal_returned.

amount_due() 每次更新 total_due 字段 table它被称为。

Edit 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')

You're looking for annotations.

您的视图集应按如下方式定义查询集:

from django.db.models import F, Sum
Contact.objects.annotate(
    total_due=Sum(
        F('amountgiven_set__total_payable')
        - F('amountgiven_set__total_returned')
    )
)

然后在序列化器上定义一个 MethodSerializer 字段来解决它。

class ContactMinSerializer(serializers.ModelSerializer):
    total_due = serializers.SerializerMethodField()

    def get_total_due(self, obj):
        return return self.total_due

    class Meta:
        model = Contact
        fields = (
            'id', 'first_name', 'created', 'modified',
            'total_due',
        )