我如何应用filter到Django REST框架中的嵌套资源?

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

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() 

我正在使用Django REST框架创build一个资源,返回区域详细信息和嵌套资源,显示该区域的已validation用户的权限。 输出应该是这样的:

 { "name": "test", "current_user_zone_permission": { "is_administrator": true, "is_active": true } } 

我已经创build了这样的序列化程序:

 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') 

与此问题是,当我请求一个特定区域时,嵌套的资源返回所有具有该区域的权限的用户的ZonePermissionlogging。 有什么办法在request.user上应用一个filter到嵌套的资源?

顺便说一句,我不希望使用HyperlinkedIdentityField这个(最小化HTTP请求)。

这是我根据下面的答案实施的解决scheme。 我将下面的代码添加到我的序列化程序类中:

 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 

非常感谢解决scheme!

我面临着同样的情况。 我find的最佳解决scheme是使用SerializerMethodField并使用该方法查询并返回所需的值。 你可以通过self.context['request'].user来访问该方法中的request.user

不过,这似乎有点破解。 我对DRF来说是相当新的,所以也许有更多经验的人可以参加。

你必须使用filter而不是get,否则如果有多个logging返回,你将得到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 

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

您可以inheritanceListSerializer并覆盖to_representation方法。

默认情况下,to_representation方法调用嵌套的查询集上的data.all()。 所以你需要在调用方法之前创builddata = data.filter(** your_filters)。 然后你需要添加你的子类ListSerializer作为list_serializer_class在嵌套序列化的元。

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

如果您在多个地方使用QuerySet / Filter,则可以在模型上使用getter函数 ,然后甚至放弃序列化程序/字段的“源”kwarg。 如果DRF在使用get_attribute函数时发现它们 ,它会自动调用函数/可调用函数。

 class Zone(models.Model): name = models.SlugField() def current_user_zone_permission(self): return ZonePermission.objects.get(zone=self, user=user) 

我喜欢这个方法,因为它保持你的API与api over HTTP一致。

 class ZoneSerializer(serializers.HyperlinkedModelSerializer): current_user_zone_permission = ZonePermissionSerializer() class Meta: model = Zone fields = ('name', 'current_user_zone_permission') 

希望这有助于一些人!

注意:名称不需要匹配,如果需要/想要,仍然可以使用源kwarg。

编辑:我只是意识到模型上的function没有访问用户或请求。 所以也许一个自定义的模型字段/ ListSerializer会更适合这个任务。

我会以两种方式之一来做。

1)要么通过在您的视图预取:

  serializer = ZoneSerializer(Zone.objects.prefetch_related( Prefetch('zone_permission_set', queryset=ZonePermission.objects.filter(user=request.user), to_attr='current_user_zone_permission')) .get(id=pk)) 

2)或通过.to_representation:

 class ZoneSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Zone fields = ('name',) def to_representation(self, obj): data = super(ZoneSerializer, self).to_representation(obj) data['current_user_zone_permission'] = ZonePermissionSerializer(ZonePermission.objects.filter(zone=obj, user=self.context['request'].user)).data return data