如何使字段代表相关对象的数量

时间:2019-07-05 17:14:24

标签: django django-rest-framework

我有几个Django模型,即Channel和Recording。通道与记录具有一对多的关系,因此一个通道可能具有许多记录。在Channel模型中,我目前有2个字段num_recordings和storage_size,它们现在被创建为Integers,但是我想作为数据库查询的结果动态生成。例如。 num_recordings应该是给定通道上当前记录的计数,而storage_size应该是给定通道上每个记录的字段“ size”的总和。

我正在使用Django rest框架提供模型的JSON表示,并希望在查询Channel时看到这两个字段为Integers,但又不想分别计算它们,例如如果查询Channel端点时,它将对记录关系进行计数,然后将其作为“ num_recordings”返回,并在该关系中的所有记录的recording.size字段中返回一个总和,并在storage_size中报告该计数,则将是理想的领域。

我该怎么做?

1 个答案:

答案 0 :(得分:1)

您可以通过受益于Django中related_name字段的ForeignKey属性和标准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模型中直接使用those methods

class Channel(models.Model):
    ...

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

现在为您的storage_size,您可以通过QuerySet的{​​{3}}方法和aggregate()聚合函数对其进行聚合:

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_recordingsstorage_size以便显示它们。由于它们以@property装饰,因此它们在设计上是只读,因此会根据相关记录进行动态计算。