首页 > 解决方案 > Django Rest Framework 使用 SerializerMethodField 返回相对路径而不是完整 url

问题描述

我遇到了一个奇怪的问题。我一直在使用 Django 和 DRF 以及在前端做出反应来开发应用程序。我的应用有两个模型,Place 和 Cover。每个地方都有一个封面图片,这里是数据库模式。

图像表

+----+---------------------+----------+----------------------+
| pk |        file         |  title   |     description      |
+----+---------------------+----------+----------------------+
|  1 | /media/my-image.jpg | My Image | My Image Description |
+----+---------------------+----------+----------------------+

放置表

+----+------+-------+
| pk | code | cover |
+----+------+-------+
|  1 | abcd |     1 |
+----+------+-------+

我的操作很简单。我将使用地点代码请求地点详细信息,DRF 将返回详细信息。这是我最初写的。

class ImageSerializer(ModelSerializer):
    class Meta:
        model = Image
        fields = ["pk", "file", "title", "description"]

class PlaceDetailSerializer(ModelSerializer):
    cover = ImageSerializer()

    class Meta:
        model = Place
        fields = ["code", "cover"]

class PlaceDetailView(RetrieveAPIView):
    serializer_class = PlaceDetailSerializer
    permission_classes = []
    queryset = Place.objects.filter(deleted=False, published=True)
    lookup_field = 'code'
    lookup_url_kwarg = 'code'

这是请求的输出

{
    "code": "3469324020",
    "cover": {
        "pk": 13,
        "file": "http://127.0.0.1:8000/media/my-image.jpg ",
        "title": "My Image",
        "description": ""
    }
}

到目前为止一切都很好。因为我想要我的图片的完整网址,而这正是我所拥有的。但是当我开始使用时就会出现问题SerializerMethodField()

class PlaceDetailSerializer(ModelSerializer):
    cover = SerializerMethodField()

    def get_cover(self, place):
        return ImageSerializer(place.cover).data

    class Meta:
        model = Place
        fields = ["code", "cover"]

这是更改后的新响应

{
    "code": "3469324020",
    "cover": {
        "pk": 13,
        "file": "/media/my-image.jpg",
        "title": "My Image",
        "description": ""
    }
}

看?DRF 不再返回绝对 URL,而是返回相对 URL。我很好奇为什么会这样?它与 DRF 上下文参数有关吗?

我还注意到绝对 url 也不适用于 APIView。

class PlaceDetailSerializer(ModelSerializer):
    cover = ImageSerializer()

    class Meta:
        model = Place
        fields = ["code", "cover"]


class PlaceDetailView( APIView ):
    serializer_class = PlaceDetailSerializer
    permission_classes = []
    queryset = Place.objects.filter(deleted=False, published=True)
    lookup_field = 'code'
    lookup_url_kwarg = 'code'

    def get(self, request, *args, **kwargs):
        place = Place.objects.get(code=kwargs.get("code"))
        return Response(PlaceDetailSerializer(place).data)

它还将返回相对 url 作为输出。


现在我知道有一些方法可以使用get_absolute_url()或其他函数返回完整的 url。但我只是好奇为什么这不适用于SerializerMethodFieldor APIView。我希望如果你知道,你可以帮助我理解这里发生了什么。


标签: djangodjango-modelsdjango-rest-frameworkdjango-serializer

解决方案


您需要使请求对序列化程序可用,如下所示:

return Response(PlaceDetailSerializer(place, context={'request': request}).data)

return ImageSerializer(place.cover, context={'request': request}).data

通常,Django Rest Framework 会为您执行此操作,但如果您手动调用序列化程序类(例如在 MethodField 中),您还必须将请求作为上下文变量传递。

查看FileField 是如何序列化的

request = self.context.get('request', None)
if request is not None:
     return request.build_absolute_uri(url)
return url

如果您不将请求作为上下文变量传递,则序列化程序无法构建绝对 URL。


推荐阅读