Django-Rest框架:自定义API响应

2024-05-19 17:07:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我有Char对象与Source对象有许多关系。因为一个字符可以出现在许多源中,而许多源代码可以包含多个字符。MtM关系通过一个through表,该表也包含页码。在我使用Django REST框架构建的API响应中,我希望避免为每个字符解析完整的源标题、作者等。相反,为了减少JSON响应的大小,我希望通过id引用它,并包含一个sources部分,以便客户机可以查找它。在

即,访问/api/char/26的客户机应得到以下响应:

"chars": [
    {
        "id": 26,
        "name": "龜",
        "locations": [
            {
                "page": 136,
                "source": 1
            },
            {
                "page": 162,
                "source": 1
            }
        ]
    }
],
"sources": [
    {
        "id": 1,
        "title": "Bruksanvisning Foamglass",
        "author": "Bluppfisk"
    }
]

以下是API视图:

^{pr2}$

以及序列化程序:

class CharSerializer(serializers.ModelSerializer):
    locations = serializers.SerializerMethodField()

    class Meta:
        model = Char
        fields = ('id', 'name', 'locations',)
        depth = 1

    def get_locations(self, obj):
        qset = CharInSource.objects.filter(char=obj)
        return [CharInSourceSerializer(m).data for m in qset]


class CharInSourceSerializer(serializers.ModelSerializer):
    class Meta:
        model = CharInSource
        fields = ('page', 'source',)

问题是我不知道如何钩住generics.RetrieveAPIView类,这样它将包含相关源的列表。我一直在挖掘源代码,但我甚至不知道如何获得pk值。在


Tags: 对象apiidsource客户机源代码关系page
2条回答

这可以通过在您的CharSerializer上的另一个SerializerMethodField并创建一个SourceSerializer;不将基方法扩展到GenericAPIView or RetrieveModelMixin。在

def SourceSerializer(ModelSerializer):
    class Meta:
         model = Source
         fields = ('id', 'title', 'author') # assuming author is not also a
                                            #  ForeignKey, otherwise returns an id

def CharSerializer(...):
....
sources = SerializerMethodField()
def get_sources(self, obj):
    return SourceSerializer(
         Source.objects.filter(chars__in=[obj.id]).distinct(), 
             many=True).data
class Meta:
    fields = (...,'sources')

假设与MTM模型相关的名称的属性是chars,那么可以使用chars__in并传递一个Charid的列表;在本例中,这是我们引用的单个字符。但是,这将包含每个char对象内的源,而不是问题所指出的外部。但是,我想您可能想知道哪些源代码具有哪个字符,正如我的解决方案所提供的那样。在

如果不了解模型的确切结构,我就无法确定您应该如何检索源对象。我觉得您也可以用obj.sources.all()代替SourceSerializer中笨拙的__in查询。在

最后,我通过重写视图的retrieve方法,最终解决了这个问题。在

class CharAPIView(generics.RetrieveAPIView):
    queryset = Char.objects.all()

    def retrieve(self, *args, **kwargs):
        instance = self.get_object()
        char = CharSerializer(instance).data
        qset = Source.objects.all()
        sources = [SourceSerializer(m).data for m in [i for i in instance.location.all()]]

        return Response({
            'char': char,
            'sources': sources,
        })

相关问题 更多 >