首页 > 解决方案 > 如何让一个字段表示相关对象的数量

问题描述

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

我正在使用 Django rest 框架来提供模型的 JSON 表示,并希望它这样当我查询 Channel 时,我将这两个字段视为整数,但不想单独计算它们,例如它会如果当您查询 Channel 端点时,它将对记录关系执行计数,并将其作为“num_recordings”返回,并在关系中的所有记录的recording.size 字段上返回总和,并在 storage_size 字段上报告,这是理想的选择。

我怎样才能做到这一点?

标签: djangodjango-rest-framework

解决方案


您可以通过受益于 Django 和标准 Python装饰器related_name中的字段属性来处理它。ForeignKey@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特定的相关:channelchannel

>>> 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()聚合它:QuerySetSum

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,因此它们在设计上是只读的,因此是根据相关记录动态计算的。


推荐阅读