【问题标题】:Django serializer Imagefield to get full URLDjango 序列化器 Imagefield 以获取完整的 URL
【发布时间】:2016-06-02 01:22:05
【问题描述】:

我是 Django 的初学者,目前我可以像这样构建模型。

模型.py

class Car(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    photo = models.ImageField(upload_to='cars')

序列化器.py

class CarSerializer(serializers.ModelSerializer):
    class Meta:
        model = Car
        fields = ('id','name','price', 'photo') 

views.py

class CarView(APIView):
    permission_classes = ()
    def get(self, request):
        car = Car.objects.all()
        serializer = CarSerializer(car)
        return Response(serializer.data)

对于照片,它不显示完整的 URL。如何显示完整的 URL?

【问题讨论】:

标签: python django django-rest-framework


【解决方案1】:

Django 没有提供存储在models.ImageField 中的图像的绝对 URL(至少如果您不包含在 MEDIA_URL 中的域名;不建议包含域,除非您托管您的不同服务器(例如 aws)上的媒体文件)。

但是,您可以修改序列化程序以使用自定义 serializers.SerializerMethodField 返回照片的绝对 URL。在这种情况下,您的序列化程序需要进行如下更改:

class CarSerializer(serializers.ModelSerializer):
    photo_url = serializers.SerializerMethodField()

    class Meta:
        model = Car
        fields = ('id','name','price', 'photo_url') 

    def get_photo_url(self, car):
        request = self.context.get('request')
        photo_url = car.photo.url
        return request.build_absolute_uri(photo_url)

还要确保您已设置 Django 的 MEDIA_ROOTand MEDIA_URL 参数,并且您可以通过浏览器访问照片 http://localhost:8000/path/to/your/image.jpg

正如 piling 所指出的,您需要在 views.py 中初始化序列化程序时添加请求:

def my_view(request):
    …
    car_serializer = CarSerializer(car, context={"request": request})
    car_serializer.data

【讨论】:

  • 还需要在views.py中修改吗?我在 Serializers.py 中更改了您的错误后出现错误。 __init__() 正好接受 2 个参数(1 个给定)
  • 不确定是否可以将 QuerySet 添加到 Serializer 类中。你能用一个元素试试吗serializer = CarSerializer(car[0])
  • 我仍然有这个错误。我在这里上传了我的项目。如果有必要也检查设置。 mediafire.com/download/wj3ey2pfx3ygyf5/todoapi.zip
  • 看起来您将 photo_url 放在了 Meta 类中。将它放在上面的一个范围内,它应该可以解决问题。
  • 如果不试试这个; serialized_car = CarSerializer(Car, context={"request": request})
【解决方案2】:

对于未来的访问者,如果视图方法已经返回了序列化对象,则无需向序列化程序添加另一个字段。唯一需要的是添加上下文,因为它需要生成超链接,如drf documentation中所述

@list_route()
def my_view(self, request):
    qs = Object.objects.all()
    return Response(MySerializer(qs, many=True, context={'request': request}).data)

【讨论】:

  • 当使用 django rest 框架视图时,上下文会自动传递。如果您随后使用嵌套的序列化程序而不传递上下文,那么您最终会陷入混乱的境地。所以很高兴知道这一点!
  • 我正在使用 django rest 框架,并且需要此解决方案来输出完全限定的 URL 路径。
【解决方案3】:

序列化器类

class CarSerializer(serializers.ModelSerializer):

  photo_url = serializers.ImageField(max_length=None, use_url=True, allow_null=True, required=False)
  class Meta:
      model = Car
      fields = ('id','name','price', 'photo_url')

查看

class CarView(APIView):

    def get(self, request, *args, **kwargs):

        queryset = Car.objects.all()

        serializer = CarSerializer(queryset, many=True, context={"request":request})

        return Response(serializer.data, status=status.HTTP_200_OK)

【讨论】:

    【解决方案4】:

    最好使用这段代码,因为上面的代码没有检查图像是否可以为空。

    class CarSerializer(serializers.ModelSerializer):
          photo_url = serializers.SerializerMethodField()
    
          class Meta:
                model = Car
                fields = ('id','name','price', 'photo_url') 
    
          def get_photo_url(self, car):
                request = self.context.get('request')
                if photo and hasattr(photo, 'url'):
                   photo_url = car.photo.url
                   return request.build_absolute_uri(photo_url)
                else:
                   return None
    

    【讨论】:

      【解决方案5】:

      序列化器.py

       class BannerSerializer(serializers.ModelSerializer):
              image = serializers.SerializerMethodField()
              def get_image(self, obj):
                  return self.context['request'].build_absolute_uri( obj.image.url)
      

      views.py

                  banner = Banner.objects.all()
                  banner_data = BannerSerializer(banner,many=True, context={'request': request})
                  data = banner_data.data
                  return Response({"data":data})
      

      【讨论】:

      • 仅供参考:很好的答案,但这不适用于默认的 Django 文件存储引擎以外的任何东西。
      【解决方案6】:

      我阅读了Serializer的实现,发现最简单的方法是扩展ImageField:

      from django.db import models
      
      class ImageField(models.ImageField):
          def value_to_string(self, obj): # obj is Model instance, in this case, obj is 'Class'
              return obj.fig.url # not return self.url
      
      class Class(models.Model):
          name = models.CharField(max_length=50)
          intro = models.CharField(max_length=200)
          # fig = models.ImageField(upload_to="classes")
          fig = ImageField(upload_to="classes") 
      
          def __str__(self):
              return repr(self,"name")
      

      【讨论】:

        猜你喜欢
        • 2018-10-16
        • 1970-01-01
        • 2013-03-23
        • 2010-10-27
        • 2011-11-21
        • 1970-01-01
        • 2013-09-15
        • 2021-04-05
        • 2017-07-10
        相关资源
        最近更新 更多