Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django REST框架和文件字段绝对url_Python_Django_Url_Filefield - Fatal编程技术网

Python Django REST框架和文件字段绝对url

Python Django REST框架和文件字段绝对url,python,django,url,filefield,Python,Django,Url,Filefield,我定义了一个简单的Django应用程序,其中包括以下模型: class Project(models.Model): name = models.CharField(max_length=200) thumbnail = models.FileField(upload_to='media', null=True) (技术上是的,这可能是一个ImageField。) 在模板中,很容易将媒体URL值(在settings.py中正确编码)作为前缀包含到缩略图URL中。以下工作很好:

我定义了一个简单的Django应用程序,其中包括以下模型:

class Project(models.Model):
    name = models.CharField(max_length=200)
    thumbnail = models.FileField(upload_to='media', null=True)
(技术上是的,这可能是一个ImageField。)

在模板中,很容易将媒体URL值(在settings.py中正确编码)作为前缀包含到缩略图URL中。以下工作很好:

<div id="thumbnail"><img src="{{ MEDIA_URL }}{{ current_project.thumbnail }}" alt="thumbnail" width="400" height="300" border="0" /></div>
我定义了一个非常简单的ModelViewSet子体:

class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
生成的JSON示例如下所示:

{
    "id": 1, 
    "url": "http://localhost:8000/api/v1/projects/1/", 
    "name": "Institutional", 
    "thumbnail": "media/institutional_thumb_1.jpg"
}
我还没有弄清楚如何在项目的JSON表示中提供包含图像完整url的缩略图字段

我想我需要在ProjectSerializer中创建一个自定义字段,但没有成功。

试试看

示例(未测试):

请求必须对序列化程序可用,以便它可以为您构建完整的绝对URL。一种方法是在创建序列化程序时显式传递它,类似于:

serializer = MySerializer(account, context={'request': request})

谢谢,沙文沃瑟。您的示例和文档参考非常有帮助。我的实现略有不同,但非常接近您发布的内容:

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

要获取使用FileField的文件的url,只需调用FieldFile的url属性(这是文件实例而不是字段),它使用存储类来确定此文件的url。如果您使用像AmazonS3这样的外部存储,或者如果您的存储发生了变化,那么这非常简单

获取缩略图的url如下所示

def get_thumbnail_url(self, obj):
    return obj.thumbnail.url
您也可以通过以下方式在模板中使用它:

{{ current_project.thumbnail.url }}

我发现为序列化方法字段编写相同的代码很烦人。 如果已将
MEDIA\u ROOT
正确设置为S3 bucket URL,则可以向序列化程序添加一个字段,如:

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

    class Meta:
        model = Project
徽标是模型中的一个图像字段。它不能为null,以避免出现类似
ValueError的错误:“img”属性没有与其关联的文件。

我只在serializer methodfield中使用
.build\u absolute\u uri
,以返回使用API中其他视图的绝对URL。例如,在我的项目中,有一个URL
/webviews/projects/
,其中显示了一个标题和一个按钮,该按钮收集了一些用户输入(也就是说,与后缀不完全一样,因为它不是资源的简单表示,而是包含一些逻辑)。端点
/projects/
包含一个字段“webview\u url”,该字段由SerializerMethodField生成。这不是媒体。

检查您的设置。py

媒体设置

我也犯了同样的错误,发现:

媒体URL='/MEDIA/' 成功了

以前我只有:


MEDIA_URL='MEDIA/'

只需传递上下文并传递请求对象。如果您使用的是@api\u视图

serializer = CustomerSerializer(customer, context={"request": request})
对于ViewSet用户,获取\u序列化程序\u上下文方法

class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer

def get_serializer_context(self):
    return {'request': self.request}

不需要任何覆盖或自定义。DRF会自动处理它。查看
文件字段的
to_表示方法

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

context = {'request': request}
serializer = ExampleSerializer(instance, context=context)
return Response(serializer.data)

在我的例子中,重写到_表示方法是正确的

# models.py
class DailyLove(models.Model):
    content = models.CharField(max_length=1000)
    pic = models.FileField(upload_to='upload/api/media/DailyLove/')
    date = models.DateTimeField(auto_created=True)

    def __str__(self):
        return str(self.date)

# serializers.py
class DailyLoveSerializer(serializers.HyperlinkedModelSerializer):
    def to_representation(self, instance):
        representation = super(DailyLoveSerializer, self).to_representation(instance)
        representation['pic_url'] = self.context['request'].build_absolute_uri('/' + instance.pic.url)
        return representation

    class Meta:
        model = DailyLove
        fields = '__all__'

# views.py
class DailyLoveViewSet(viewsets.ModelViewSet):
    queryset = DailyLove.objects.all().order_by('-date')
    serializer_class = DailyLoveSerializer

# result
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "url": "http://localhost:8088/daily/3/",
        "date": "2019-05-04T12:33:00+08:00",
        "content": "123",
        "pic": "http://localhost:8088/daily/upload/api/media/DailyLove/nitish-meena-37745-unsplash.jpg",
        "pic_url": "http://localhost:8088/upload/api/media/DailyLove/nitish-meena-37745-unsplash.jpg"
    }
]
只需传递此
“context={'request':request}”
参数,在该参数中调用模型序列化程序类来序列化对象。您可以按照下面的代码片段获取完整的URL字段

serialized_object = serializers.MySerializer(data, many=true, context={'request': request})
检查这个

class FileFieldWithLinkRepresentation(serializers.FileField):

    def to_representation(self, value):
        return create_link(value.url, self.context['request'])
创建链接
方法:

def create_link(path: str, request: Request):
    domain = request.META['HTTP_HOST']
    if not path.startswith('/', 0, 1):
        path = '/' + path
    return request.scheme + "://" + domain + path
您可以在每个需要超链接的类中使用带有链接表示的
filefield

文件字段的表示形式

如果无法使用视图集访问Serializer中的额外上下文,请尝试在URL.py中使用基本名称注册路由器:


router.register('projects',ProjectViewSet,basename='project')
您不需要导入setting.MEDIA\u URL。只需返回:obj.thumboil.url您不需要传递
请求
。它已经在
self.context['view'].request
中可用。问题是
SerializerMethodField
在我的案例中是只读的,只要在实例化序列化程序时设置
context={'request':request}
。不需要
SerializerMethodField
。它不应该是
obj.thumboil.url
,而不是
self.thumboil\u url
这个答案让我意识到使用
context={'request':request}
作为序列化程序参数,如果从另一个域访问,文件字段将返回绝对URL。这里的重要一点是使用文件字段(而不是URL字段)并将请求添加到上下文中。ListAPIView存在问题,您的上下文解决方案正在运行!非常感谢
class FileFieldWithLinkRepresentation(serializers.FileField):

    def to_representation(self, value):
        return create_link(value.url, self.context['request'])
def create_link(path: str, request: Request):
    domain = request.META['HTTP_HOST']
    if not path.startswith('/', 0, 1):
        path = '/' + path
    return request.scheme + "://" + domain + path