Django Rest Framework - 自动注释查询集

Posted

技术标签:

【中文标题】Django Rest Framework - 自动注释查询集【英文标题】:Django Rest Framework - automatically annotate queryset 【发布时间】:2018-06-17 15:01:31 【问题描述】:

我在项目的许多不同地方都使用了一个Serializer。我需要使用一个注释,但问题是我不想在所有视图中都对其进行注释,所以我想在 Serializer 本身中进行通用注释。

有可能吗?

现在我需要在每次序列化之前这样做:

City.objects....filter....annotate(
                number_of_users_here_now=Count('current_userprofiles'))

我试过了:

class NumberOfUsersInCityNowField(serializers.Field):
    def to_native(self, value):
        count = value.annotate(
            number_of_users_here_now=Count('current_userprofiles'))['current_userprofiles__count']
        return count


class CityMapSerializer(serializers.ModelSerializer):
    number_of_users_here_now = NumberOfUsersInCityNowField()

    class Meta:
        model = City
        fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address')

这个Serializer 返回:

/api/ajax-check-trip-creation 处的 AttributeError 得到 AttributeError 尝试获取字段 number_of_users_here_now 的值时 序列化程序CityMapSerializer。序列化器字段可能被命名 不正确且不匹配 City 实例上的任何属性或键。 原始异常文本是:“城市”对象没有属性 'number_of_users_here_now'。

编辑

class NumberOfUsersInCityNowField(serializers.PrimaryKeyRelatedField):
    def get_queryset(self):
        return City.objects.annotate(
        number_of_users_here_now=Count('current_userprofiles'))

class CityMapSerializer(serializers.ModelSerializer):
    # number_of_users_here_now = serializers.IntegerField()
    number_of_users_here_now = NumberOfUsersInCityNowField()
    class Meta:
        model = City
        fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address')

但是

serializers.CityMapSerializer(City.objects.all()[:3],many=True).data

仍然返回:

AttributeError: 'City' object has no attribute 'number_of_users_here_now'

【问题讨论】:

你在模型中有相同的字段名吗? 不,这不是原生字段。我需要为每个城市添加用户配置文件的数量。 【参考方案1】:

您可以将查询集的count 方法与SerializerMethodField 一起使用:

class CityMapSerializer(serializers.ModelSerializer):
    number_of_users_here_now = SerializerMethodField()

    def get_number_of_users_here_now (self, obj):
        return obj.current_userprofiles.count()

UPD

为了避免 n+1 查询,您可以尝试实现NumberOfUsersInCityNowField 序列化程序的get_queryset 方法:

class NumberOfUsersInCityNowField(serializers.PrimaryKeyRelatedField):
    def get_queryset(self):
        return City.objects.annotate(
        number_of_users_here_now=Count('current_userprofiles'))['current_userprofiles__count']

【讨论】:

我不想避免这样做,因为它访问每个城市的数据库,而不是像注释那样只访问一次。 @MilanoSlesarik 是的,你是对的,尝试从 PrimaryKeyRelatedField 继承并覆盖 get_queryset 方法。 您的解决方案似乎是我想要的,但不幸的是它返回了相同的错误。我已经在问题的底部添加了代码。 城市是模型 UserProfile 中的外键,related_name='current_userprofiles' @MilanoSlesarik 抱歉,无法为您提供更好的建议。如果您找不到解决方案,您可能应该尝试实现注释的 mixin 类并将其添加到您的所有视图中。

以上是关于Django Rest Framework - 自动注释查询集的主要内容,如果未能解决你的问题,请参考以下文章

Django rest framework 之 DictField、ListField、自定义字段

python 使用Django Rest Framework在Django中自定义用户实现

django-rest-framework 自定义视图集检索多个查找参数

与 Django Rest Framework 的非用户连接的自定义身份验证

Django Rest Framework 自定义身份验证

Django REST Framework 创建自定义用户