Могу ли я добавить пользовательский метод в Django queryset? - PullRequest
1 голос
/ 16 января 2020

Предположим, у меня есть две модели в отношении один ко многим:

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 года, но ответы кажутся немного устаревшими и не работают. Я сейчас использую django 2.2.

1 Ответ

3 голосов
/ 16 января 2020

Да, вы можете создать подкласс класса QuerySet, например:

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

class <b>CustomQuerySet</b>(QuerySet):

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

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

Обратите внимание, что здесь более эффективно совершать .aggregate(..) вызовы [Django -doc] здесь, поскольку они будут запускать агрегат на базе данных , а не на уровне Django / Python.

Далее мы можем создать собственный менеджер с наш CustomQuerySet как _queryset_class:

from django.db import models

class <b>CustomManager</b>(models.Manager):
    <b>_queryset_class = CustomQuerySet</b>

и затем мы можем добавить менеджера в нашу модель:

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

    <b>objects = CustomManager()</b>
...