如何在Django REST框架中将过滤器应用于嵌套资源?

Dav*_*ull 57 django django-rest-framework

在我的应用程序中,我有以下模型:

class Zone(models.Model):
    name = models.SlugField()

class ZonePermission(models.Model):
    zone = models.ForeignKey('Zone')
    user = models.ForeignKey(User)
    is_administrator = models.BooleanField()
    is_active = models.BooleanField()
Run Code Online (Sandbox Code Playgroud)

我正在使用Django REST框架来创建一个返回区域详细信息的资源,以及一个显示该区域的经过身份验证的用户权限的嵌套资源.输出应该是这样的:

{
    "name": "test", 
    "current_user_zone_permission": {
        "is_administrator": true, 
        "is_active": true
    }
} 
Run Code Online (Sandbox Code Playgroud)

我已经创建了这样的序列化器:

class ZonePermissionSerializer(serializers.ModelSerializer):
    class Meta:
        model = ZonePermission
        fields = ('is_administrator', 'is_active')

class ZoneSerializer(serializers.HyperlinkedModelSerializer):
    current_user_zone_permission = ZonePermissionSerializer(source='zonepermission_set')

    class Meta:
        model = Zone
        fields = ('name', 'current_user_zone_permission')
Run Code Online (Sandbox Code Playgroud)

这样做的问题是,当我请求特定区域时,嵌套资源会为具有该区域权限的所有用户返回ZonePermission记录.有没有办法对request.user嵌套资源应用过滤器?

顺便说一下,我不想使用HyperlinkedIdentityField这个(最小化http请求).

解

这是我根据下面的答案实现的解决方案.我将以下代码添加到我的序列化程序类:

current_user_zone_permission = serializers.SerializerMethodField('get_user_zone_permission')

def get_user_zone_permission(self, obj):
    user = self.context['request'].user
    zone_permission = ZonePermission.objects.get(zone=obj, user=user)
    serializer = ZonePermissionSerializer(zone_permission)
    return serializer.data
Run Code Online (Sandbox Code Playgroud)

非常感谢您的解决方案!

小智 29

我面临同样的情况.我发现的最佳解决方案是使用a SerializerMethodField并使用该方法查询并返回所需的值.您可以request.user通过该方法访问self.context['request'].user.

不过,这似乎有点像黑客.我对DRF很新,所以也许有经验丰富的人可以加入.


Ibr*_*him 8

您必须使用filter而不是get,否则如果多个记录返回,您将获得Exception.

current_user_zone_permission = serializers.SerializerMethodField('get_user_zone_permission')

def get_user_zone_permission(self, obj):
    user = self.context['request'].user
    zone_permission = ZonePermission.objects.filter(zone=obj, user=user)
    serializer = ZonePermissionSerializer(zone_permission,many=True)
    return serializer.data
Run Code Online (Sandbox Code Playgroud)


inp*_*ive 5

现在你可以使用我在这里描述的方法继承ListSerializer:https://stackoverflow.com/a/28354281/3246023

您可以继承ListSerializer并覆盖to_representation方法.

默认情况下,to_representation方法在嵌套查询集上调用data.all().因此,您需要在调用方法之前生成data = data.filter(**your_filters).然后,您需要在嵌套序列化程序的元数据上添加子类ListSerializer作为list_serializer_class.

  1. 子类ListSerializer,覆盖to_representation然后调用super
  2. 在嵌套的Serializer上添加子类ListSerializer作为元list_serializer_class