Django REST Framework and FileField absolute url

前端 未结 11 795
不知归路
不知归路 2020-12-13 02:10

I\'ve defined a simple Django app that includes the following model:

class Project(models.Model):
    name = models.CharField(max_length=200)
    thumbnail =         


        
相关标签:
11条回答
  • 2020-12-13 02:45

    Thanks, shavenwarthog. Your example and documentation reference helped enormously. My implementation is slightly different, but very close to what you posted:

    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') 
    
    0 讨论(0)
  • 2020-12-13 02:51

    if you cannot access extra context in your seriralizer using Viewsets, try register your router with a basename in urls.py:

    router.register('projects', ProjectViewSet, basename='project')

    you can use build_absolute_uri:

    def get_thumbnail_url(self, obj):
        return self.context.get('request').build_absolute_uri(obj.thumbnail.url)

    0 讨论(0)
  • 2020-12-13 02:52

    To get the url of a file which uses FileField you can just call the url attribute of the FieldFile (this is the file instance not the field), it use the Storage class to determine the url for this file. It's very straightforward if you are using a external storage like Amazon S3 or if your storage changes.

    The get_thumbnail_url would be like this.

    def get_thumbnail_url(self, obj):
        return obj.thumbnail.url
    

    You can also use it in the template this way:

    {{ current_project.thumbnail.url }}
    
    0 讨论(0)
  • 2020-12-13 02:53

    No need for any overrides or customizations. DRF handles it automatically. Take a look at to_representation method of 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
    

    Note that it won't work if the context of the serializer is not set properly. If you're using ViewSets, no worries, everything is done silently but if you're instantiating the serializer manually you have to pass in the request in the context.

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

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

    0 讨论(0)
  • 2020-12-13 02:56

    Check you settings.py

    media settings.

    I had same error and found that:

    MEDIA_URL = '/media/' did the trick.

    Before i only had:

    MEDIA_URL = 'media/'

    0 讨论(0)
  • 2020-12-13 02:57

    In my case, override to_representation method works right.

    # 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"
        }
    ]
    
    0 讨论(0)
提交回复
热议问题