【问题标题】:In Django Rest Framework, how to restrict fields fetched with a RelatedField Serializer relation?在 Django Rest Framework 中,如何限制使用 RelatedField 序列化器关系获取的字段?
【发布时间】:2018-04-13 13:29:42
【问题描述】:

以序列化器from the DRF docs为例:

class AlbumSerializer(serializers.ModelSerializer):

    tracks = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='track-detail'
    )

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

当 DRF 执行查询以获取特定 album 的所有 tracks 时,生成的 SQL 会选择每个 track 的列中的所有。我将如何将其限制为仅请求特定列,例如pk 将用于响应中每个轨道的超链接?

(为什么?因为可能返回了 lot 的曲目,并且每个曲目在数据库中的行中都有 lot 的数据,这可能是很多返回不必要的数据。)

【问题讨论】:

标签: django django-rest-framework


【解决方案1】:

您可以使用SerializerMethodField 自己构建查询集并使用value_list

class AlbumSerializer(serializers.ModelSerializer):

    tracks = serializers.SerializerMethodField()

    def get_tracks(self, instance):
        return TracK.objects.filter(album=self).values_list('id', flat=True)


    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

【讨论】:

  • 我可以看到你要去哪里但是......如果我返回instance.tracks.values_list(flat=True) 那么它只是所有相关曲目的所有数据的列表。我可以获得instance.tracks.values('pk'),这是我需要的数据,但是我需要使用DRF 的reverse_lazy() 方法构造一个API URL 列表,这需要request 对象,这里无法访问。嗯。
  • 我忘记了更重要的: values_list(flat=True) => values_list('id', flat=True) ,对不起 :)
  • 啊,好点子!这适用于仅返回轨道的ids,因此它适用于更简单的情况,但不能获取所有 URL。我将修改我的答案的简单版本。
【解决方案2】:

我认为这样做...

from rest_framework import serializers
from rest_framework.reverse import reverse

from myapp.models import Album


class AlbumSerializer(serializers.ModelSerializer):

    tracks = serializers.SerializerMethodField()

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

    def get_tracks(self, instance):
        "Returns a list of URLs for Tracks' API detail views"

        request = self.context.get('request')

        tracks = []

        for track in instance.tracks.values('pk'):
            tracks.append(reverse(
                                'track-detail',
                                kwargs={'pk': track['pk']},
                                request=request
                            ))

        return tracks

我们正在手动创建 HyperlinkedRelatedField() 的结果(将 URL 列表返回到曲目的 API 详细信息页面),但在查询集中使用 values() 限制从数据库中获取的数据。

这假定track-detail URL 模式的参数为pk

替换PrimaryKeyRelatedField() 更加简单。将上面的 get_tracks() 方法替换为:

    def get_tracks(self, instance):
        "Returns a list of Track IDs"
        return instance.tracks.values_list('pk', flat=True)

感谢@jmny 引导我使用SerializerMethodField()

【讨论】:

  • 注意:最初我使用reverse_lazy() 来生成URL,而不是reverse(),但是当Django 的缓存打开时(Django 的locmem.LocMemCache 或memcached 与PyLibMCCache),这会产生错误结果将被缓存:“无法序列化'_io.BufferedReader'对象”或“无法序列化'_io.TextIOWrapper'对象”。
猜你喜欢
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 2014-01-05
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
相关资源
最近更新 更多