我可以向Django查询集添加自定义方法吗?

时间:2020-01-15 21:21:33

标签: django django-models django-queryset

假设我有两个模型,一对多关系:

from django.db import models

class Quantity(models.Model):
    name = models.CharField(max_length=64)


class Measurement(models.Model):
    value = models.FloatField()
    date = models.DateField()
    quantity = models.ForeignKeyField(Quantity, on_delete=models.CASCADE)

我做了一些记录...

weight = Quantity.objects.create(name="Body Weight in kg")
Measurement.objects.create(value=80, date="2020-01-01", quantity=weight)
Measurement.objects.create(value=81, date="2020-01-02", quantity=weight)
Measurement.objects.create(value=80.6, date="2020-01-03", quantity=weight)
Measurement.objects.create(value=80.1, date="2020-01-04", quantity=weight)
Measurement.objects.create(value=79.5, date="2020-01-05", quantity=weight)
Measurement.objects.create(value=81, date="2020-01-06", quantity=weight)
Measurement.objects.create(value=81, date="2020-01-07", quantity=weight)

无论如何,我可以像这样从查询集中计算指标...

weight.measurement_set.all().average()
weight.measurement_set.filter(date__gt="2020-01-04").average()
weight.measurement_set.all().sum()

...在某处定义相关方法的地方...

def average(queryset):
   return sum([m.value for m in queryset]) / queryset.count())

def average(queryset):
   return sum([m.value for m in queryset])

我从2011年开始读过this post,但答案似乎有点过时了,似乎没有用。我目前正在使用django 2.2。

1 个答案:

答案 0 :(得分:3)

是的,您可以继承QuerySet类,例如:

from django.db.models import Avg, Sum
from django.db.models.query import QuerySet

class CustomQuerySet(QuerySet):

    def average(self):
        return self.aggregate(_total=Avg('value'))['_total']

    def sum(self):
        return self.aggregate(_total=Sum('value'))['_total']

请注意,在此处制作.aggregate(..) calls [Django-doc]效率更高,因为它们将在数据库而非Django / Python级别上运行聚合。

接下来,我们可以使用CustomQuerySet作为_queryset_class来创建自定义经理:

from django.db import models

class CustomManager(models.Manager):
    _queryset_class = CustomQuerySet

然后我们可以在模型中添加一个经理:

class Measurement(models.Model):
    value = models.FloatField()
    date = models.DateField()
    quantity = models.ForeignKeyField(Quantity, on_delete=models.CASCADE)

    objects = CustomManager()