Django REST Framework和FileField绝对URL

Mar*_*sel 27 python django url filefield

我已经定义了一个包含以下模型的简单Django应用程序:

class Project(models.Model):
    name = models.CharField(max_length=200)
    thumbnail = models.FileField(upload_to='media', null=True)
Run Code Online (Sandbox Code Playgroud)

(从技术上讲,这可能是一个ImageField.)

在模板中,将MEDIA_URL值(在settings.py中正确编码)作为缩略图URL的前缀包含在内是很容易的.以下工作正常:

<div id="thumbnail"><img src="{{ MEDIA_URL }}{{ current_project.thumbnail }}" alt="thumbnail" width="400" height="300" border="0" /></div>
Run Code Online (Sandbox Code Playgroud)

使用DRF,我定义了一个名为ProjectSerializer的HyperlinkedModelSerializer后代:

class ProjectSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Project
        fields = ( 'id' ,'url', 'name', 'thumbnail')
Run Code Online (Sandbox Code Playgroud)

我已经定义了一个非常简单的ModelViewSet后代:

class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
Run Code Online (Sandbox Code Playgroud)

生成的JSON示例如下所示:

{
    "id": 1, 
    "url": "http://localhost:8000/api/v1/projects/1/", 
    "name": "Institutional", 
    "thumbnail": "media/institutional_thumb_1.jpg"
}
Run Code Online (Sandbox Code Playgroud)

我还没有弄清楚如何在项目的JSON表示中提供包含图像完整URL的缩略图字段.

我认为我需要在ProjectSerializer中创建一个自定义字段,但还没有成功.

joh*_*all 48

尝试使用SerializerMethodField

示例(未经测试):

class MySerializer(serializers.ModelSerializer):
    thumbnail_url = serializers.SerializerMethodField('get_thumbnail_url')

    def get_thumbnail_url(self, obj):
        return self.context['request'].build_absolute_uri(obj.thumbnail_url)
Run Code Online (Sandbox Code Playgroud)

该请求必须可供序列化程序使用,因此它可以为您构建完整的绝对URL.一种方法是在创建序列化程序时显式传入它,类似于:

serializer = MySerializer(account, context={'request': request})
Run Code Online (Sandbox Code Playgroud)

  • 在我的例子中,只需在实例化序列化程序时设置`context = {'request':request},就足以获得绝对URL.不需要`SerializerMethodField`. (13认同)
  • 这个问题是```SerializerMethodField```是只读的 (2认同)
  • 不应该是`obj.thumbnail.url`,而不是`self.thumbnail_url` (2认同)
  • 这个答案让我意识到,使用 context={'request': request}` 作为序列化器参数,如果从另一个域访问,文件字段将返回绝对 URL。 (2认同)

Mar*_*sel 7

谢谢,shavenwarthog.您的示例和文档参考帮助极大.我的实现略有不同,但与您发布的内容非常接近:

from SomeProject import settings

class ProjectSerializer(serializers.HyperlinkedModelSerializer):

    thumbnail_url = serializers.SerializerMethodField('get_thumbnail_url')

    def get_thumbnail_url(self, obj):
        return '%s%s' % (settings.MEDIA_URL, obj.thumbnail)

    class Meta:
        model = Project
        fields = ('id', 'url', 'name', 'thumbnail_url') 
Run Code Online (Sandbox Code Playgroud)

  • 您无需导入setting.MEDIA_URL.只需返回:obj.thumbnail.url (3认同)

小智 6

要获取使用FileField的文件的url,您只需调用FieldFile的url属性(这是文件实例而不是字段),它使用Storage类来确定此文件的URL.如果您使用Amazon S3等外部存储或存储更改,则非常简单.

get_thumbnail_url就是这样的.

def get_thumbnail_url(self, obj):
    return obj.thumbnail.url
Run Code Online (Sandbox Code Playgroud)

您也可以这样在模板中使用它:

{{ current_project.thumbnail.url }}
Run Code Online (Sandbox Code Playgroud)


Edu*_*nal 6

我发现为序列化方法字段编写相同的代码很烦人。如果您已正确设置了MEDIA_ROOTS3 存储桶 URL,则可以向序列化程序添加一个字段,例如:

class ProjectSerializer(serializers.ModelSerializer):
    logo_url = serializers.URLField(read_only=True, source='logo.url')

    class Meta:
        model = Project
Run Code Online (Sandbox Code Playgroud)

logo 是模型中的 ImageField。它不能为空,以避免出现类似的错误ValueError: The 'img' attribute has no file associated with it.

我只.build_absolute_uri在序列化程序方法字段中使用来返回在我的 API 中使用其他视图的绝对 url。例如,在我的项目中,有一个/webviews/projects/<pk>显示URL 、一个标题和一个收集一些用户输入的按钮(即不完全是你会用后缀做什么,因为它不是资源的简单表示,而是包含一些逻辑)。终点/projects/<pk>/包含一个字段“webview_url”,它是用 SerializerMethodField 生成的。这不是媒体。


Moh*_*adi 5

无需任何覆盖或自定义。DRF 会自动处理它。看一下to_representation方法FileField

def to_representation(self, value):
    if not value:
        return None

    use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL)

    if use_url:
        if not getattr(value, 'url', None):
            # If the file has not been saved it may not have a URL.
            return None
        url = value.url
        request = self.context.get('request', None)
        if request is not None:
            return request.build_absolute_uri(url)
        return url
    return value.name
Run Code Online (Sandbox Code Playgroud)

请注意,如果序列化程序的上下文设置不正确,它将无法工作。如果您使用ViewSet的是s,不用担心,一切都是静默完成的,但是如果您手动实例化序列化程序,则必须在上下文中传递请求。

context = {'request': request}
serializer = ExampleSerializer(instance, context=context)
return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

https://www.django-rest-framework.org/community/3.0-announcement/#file-fields-as-urls