Как получить поле, представляющее количество связанных объектов - PullRequest
0 голосов
/ 05 июля 2019

У меня есть пара моделей Django, Channel и Recording.Каналы имеют отношение «один ко многим» с записями, так что канал может иметь много записей.В модели Channel в настоящее время у меня есть 2 поля, num_recordings и storage_size, которые сейчас создаются как целые числа, но которые я хочу динамически генерировать в результате запроса к БД.Например, num_recordings должен быть текущим количеством записей на данном канале, а storage_size должен быть суммой поля «размер» для каждой записи на данном канале.

Я использую инфраструктуру отдыха Django для представления моделей в формате JSON и хочу, чтобы при запросе к каналу я видел эти два поля как целые числа, но не хотел вычислятьотдельно, например, было бы идеально, если при запросе конечной точки канала он будет выполнять подсчет отношения записи и возвращать его как «num_recordings» и сумму в поле recording.size для всех записей в отношении и отчетачто в поле storage_size.

Как я могу это сделать?

1 Ответ

1 голос
/ 06 июля 2019

Вы можете подойти к нему, воспользовавшись атрибутом related_name полей ForeignKey в Django и стандартным декоратором Python @property.


Сначала давайте предположим, что вы определили свои отношенияв models.py вот так:

class Channel(models.Model):
    ...


class Recording(models.Model):
    channel = models.ForeignKey(Channel, on_delete=..., related_name='recordings')
    # ________________________________________________________________^
    # This is the reverse relation name, e.g. channel.recordings

Теперь вы можете получить доступ к recordings определенного channel из самого channel:

>>> channel = Channel.objects.create(...)

>>> recording1 = Recording.objects.create(channel=channel, ...)
>>> recording2 = Recording.objects.create(channel=channel, ...)

>>> channel.recordings.all()
<QuerySet [<Recording: 1>, <Recording: 2>]>

>>> channel.recordings.count()
2

Вы можете использовать эти методы непосредственно в вашей Channel модели:

class Channel(models.Model):
    ...

    @property
    def num_of_recordings(self):
        return self.recordings.count()
        # __________^ (related_name)

Теперь для вашего storage_size вы можете агрегировать его с помощью aggregate() метод QuerySet и Sum функция агрегирования:

from django.db.models import Sum


class Channel(models.Model):
    ...

    @property
    def storage_size(self):
        return self.recordings.aggregate(storage_size=Sum('size'))['storage_size']

А теперь окончательная Channel модель:

class Channel(models.Model):
    ...

    @property
    def num_of_recordings(self):
        return self.recordings.count()

    @property
    def storage_size(self):
        return self.recordings.aggregate(storage_size=Sum('size'))['storage_size']

Последний шаг заключается в добавлении этих новых свойств num_of_recordings и storage_size в ваш канальный сериализатор класса для их отображения.Поскольку они украшены @property, они только для чтения по своей конструкции и, таким образом, рассчитываются динамически на основе соответствующих записей.

...