从 Serializer 调用另一个序列化程序会弄乱 URI

Posted

技术标签:

【中文标题】从 Serializer 调用另一个序列化程序会弄乱 URI【英文标题】:Calling another serializer from the Serializer messes up URI 【发布时间】:2018-06-08 21:08:06 【问题描述】:

我处于调试模式,我想设置默认 ImageField 以返回完整的 URLlocalhost:8000/path

这是当前的 JSON 数据

 ...
 "img": "http://localhost:8000/media/outfits/1/4.png",
    "tagged_clothes": [
        
            "cloth_image": "/media/clothes/1/7.png", <- This happens when I use settings.py debugging file
            "id": 6,
            "b_clothtype": "ETC",

settings.py

MEDIA_URL = '/media/' # if I change this variable as 'localhost:8000/media/',
                      # JSON returns correct URLs but I couldn't see the image.
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'media_cdn') 

这是使用 AWS 设置的工作示例。它正确显示http://localhost:8000/media/blahblah

    # HERE is working example in AWS. It returns full URI
# AWS_ACCESS_KEY_ID = "aws key" #S3
# AWS_SECRET_ACCESS_KEY = "secret key" #S3
# AWS_FILE_EXPIRE = 200 #S3
# AWS_PRELOAD_METADATA = True #S3
# AWS_QUERYSTRING_AUTH = True #S3
# DEFAULT_FILE_STORAGE = 'asd' #S3
# STATICFILES_STORAGE = 'asd' #S3
# AWS_STORAGE_BUCKET_NAME = 'asd' #S3
# S3DIRECT_REGION = 'us-west-2' #S3

# S3_URL = '//%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME #S3
# MEDIA_URL = '//%s.s3.amazonaws.com/media/' % AWS_STORAGE_BUCKET_NAME #S3
# MEDIA_ROOT = MEDIA_URL #S3

# STATIC_URL = S3_URL + 'static/' #S3
# import datetime #S3
# two_months = datetime.timedelta(days=61) # S3
# date_two_months_later = datetime.date.today() + two_months #S3
# expires = date_two_months_later.strftime("%A, %d %B %Y 20:00:00 GMT") #S3
# AWS_HEADERS =  #S3
#   'Expires': expires,
#   'Cache-Control': 'max-age=%d' % (int(two_months.total_seconds()), ),
# 

urls.py

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

代码

这种情况只有当我在序列化程序中调用另一个Serializer时才会发生

def get_tagged_clothes(self, obj):
        clothes = obj.clothes_set;
        if obj.user != self.context['request'].user:
            clothes = clothes.filter(only_me=False)
        return CListSerializer(clothes, many=True).data <- Sending wrong URI.

【问题讨论】:

【参考方案1】:

你可以使用请求的build_absolute_uri方法:

class ClothesListSerializer(serializers.ModelSerializer):
    cloth_image = serializers.SerializerMethodField()

    class Meta:
        model = Cloth
        fields = ('cloth_image' ...)


    def get_cloth_image(self, obj):
        request = self.context.get('request')
        photo_url = obj.cloth_image.url
        return request.build_absolute_uri(photo_url)

请注意,您可能需要为此视图中的序列化程序上下文添加请求:

serializer = ClothesListSerializer(Cloth, context='request': request)

但如果您使用基于通用类的视图,这将自动完成。

【讨论】:

当我使用 AWS 时,它使正确的图像绝对 url。我必须将 build_absolute_uri 的部署和测试方法分开,而且效率低下。对不起 @JohnBaek 不确定这是否有帮助,但您可以检查get_cloth_image 中的 DEBUG 设置值:from django.conf import settingsif settings.DEBUG: 哇这工作!!!!!!!!!!!!!!!你能解释一下为什么这是有效的吗?这太棒了。干得好 @JohnBaek 当序列化程序尝试构建 url 时,它需要 request 对象。正如我在回答中所说,基于类的视图使用context dict 自动将此对象传递给序列化程序。但是当你调用第二个序列化程序时,你没有提供这个字典。所以序列化程序无法构建 url。希望现在更清楚一点:) 每次只调用obj.outfits.first().outfit_img.url 只返回MEDIA_URL + 文件名值。要制作完整的网址,您需要自己使用带有此值的request.build_absolute_urirequest.build_absolute_uri(obj.outfits.first().outfit_img.url)

以上是关于从 Serializer 调用另一个序列化程序会弄乱 URI的主要内容,如果未能解决你的问题,请参考以下文章

将数据从post传递给Serializer

在JMS Serializer上反序列化期间构造对象

nu.xom:Serializer

Django Serializer - 决定在运行时序列化哪些字段

带分页的 Rails active_model_serializer

Swift Custom Response Serializer 随机返回图像