我正在try 找出添加注释字段的最佳方法,例如将任何聚合(计算)字段添加到DRF(模型)序列化程序.我的用例只是一种情况,端点返回的字段不是存储在数据库中,而是从数据库计算出来的.

让我们看看下面的例子:

模型.py

class IceCreamCompany(models.Model):
    name = models.CharField(primary_key = True, max_length = 255)

class IceCreamTruck(models.Model):
    company = models.ForeignKey('IceCreamCompany', related_name='trucks')
    capacity = models.IntegerField()

序列化程序.py

class IceCreamCompanySerializer(serializers.ModelSerializer):
    class Meta:
        model = IceCreamCompany

所需的JSON输出:

[

    {
        "name": "Pete's Ice Cream",
        "total_trucks": 20,
        "total_capacity": 4000
    },
    ...
]

我有几个可行的解决方案,但每个都有一些问题.

Option 1: add getters to model and use SerializerMethodFields

模型.py

class IceCreamCompany(models.Model):
    name = models.CharField(primary_key=True, max_length=255)

    def get_total_trucks(self):
        return self.trucks.count()

    def get_total_capacity(self):
        return self.trucks.aggregate(Sum('capacity'))['capacity__sum']

序列化程序.py

class IceCreamCompanySerializer(serializers.ModelSerializer):

    def get_total_trucks(self, obj):
        return obj.get_total_trucks

    def get_total_capacity(self, obj):
        return obj.get_total_capacity

    total_trucks = SerializerMethodField()
    total_capacity = SerializerMethodField()

    class Meta:
        model = IceCreamCompany
        fields = ('name', 'total_trucks', 'total_capacity')

上面的代码也许可以重构一点,但它不会改变这样一个事实,即该选项将执行两个额外的SQL查询per IceCreamCompany,这不是很有效.

Option 2: annotate in ViewSet.get_queryset

模型.py as originally described.

意见.py

class IceCreamCompanyViewSet(viewsets.ModelViewSet):
    queryset = IceCreamCompany.objects.all()
    serializer_class = IceCreamCompanySerializer

    def get_queryset(self):
        return IceCreamCompany.objects.annotate(
            total_trucks = Count('trucks'),
            total_capacity = Sum('trucks__capacity')
        )

这将在单个SQL查询中获得聚合字段,但我不确定如何将它们添加到序列化程序中,因为DRF不知道我已经在QuerySet中注释了这些字段.如果我将total_trucks和total_capacity添加到序列化程序中,它将抛出一个关于模型中不存在这些字段的错误.

通过使用View,选项2可以在没有序列化程序的情况下工作,但是如果模型包含很多字段,并且JSON中只需要一些字段,那么在没有序列化程序的情况下构建端点将是一种有点丑陋的攻击.

推荐答案

可能的解决方案:

意见.py

class IceCreamCompanyViewSet(viewsets.ModelViewSet):
    queryset = IceCreamCompany.objects.all()
    serializer_class = IceCreamCompanySerializer

    def get_queryset(self):
        return IceCreamCompany.objects.annotate(
            total_trucks=Count('trucks'),
            total_capacity=Sum('trucks__capacity')
        )

序列化程序.py

class IceCreamCompanySerializer(serializers.ModelSerializer):
    total_trucks = serializers.IntegerField()
    total_capacity = serializers.IntegerField()

    class Meta:
        model = IceCreamCompany
        fields = ('name', 'total_trucks', 'total_capacity')

通过使用Serializer fields,我得到了一个小例子.这些字段必须声明为序列化程序的类属性,这样DRF就不会抛出一个关于它们的错误,而这些错误在IceCreamCompany模型中并不存在.

Python-3.x相关问答推荐

背包问题-如何减少内存使用

根据其他数据框架的列顺序从数据框架中进行 Select

pandas查找另一列中是否存在ID

如何绘制交叉验证的AUROC并找到最佳阈值?

为什么我无法在django中按月筛选事件?

Strawberry FastAPI:如何调用正确的函数?

如何在 python 中将带有时区信息的时间戳转换为 utc 时间

Django 模型类方法使用错误的 `self`

替换 .txt 文件中的项目列表

如何将列表和字典逐行组合在一起

spaCy 中的匹配模式返回空结果

从日志(log)文件中查找延迟最低的用户

pymongo 失败并出现错误未定义

为什么 Python 枚举中的可变值是同一个对象?

活动屏幕上的 PyQt4 中心窗口

如何注释一个以另一个函数作为参数的函数?

如何判断一个字符串是否包含有效的 Python 代码

AttributeError:LinearRegression 对象没有属性coef_

为 Python 3 和 PyQt 构建可执行文件

Beautifulsoup 的单元测试失败