Django-Rest-Framework APIView返回模型对象和图像

时间:2017-11-15 14:00:04

标签: python django django-rest-framework

假设我想在APIView.get中返回一个包含2个属性的(非模型)对象,其中一个是模型对象,另一个是二进制图像

我尝试了几种方法,并且遇到了序列化程序的问题。

谢谢!

串行:

class MyCustomSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyCustom
        fields = '__all__'

查看:

class MyCustomGet(APIView):
    def get(self, request, format=None):
        serializer = MyCustomSerializer
        obj = s.get_custom()
        return Response({"obj": serializer(obj.obj).data, "image": obj.image})

get_custom:

class CustomClass:
    obj = None
    image = None

def get_custom():
    r = CustomClass()
    r.obj = MyCustom.objects.all().first()
    r.image = PIL.Image.open('file/path.png')
    return r

3 个答案:

答案 0 :(得分:3)

您正尝试在JSON响应(字符串)中呈现图像(二进制数据)。这不行。如果要在JSON字符串中传递图像,则必须将其编码为字符串,然后在客户端对其进行解码。一个常见的例子是base64编码的字符串:

import io
import base64

...
def get_custom():
    ...
    image = PIL.Image.open('file/path.png')
    stream = io.StringIO()
    image.save(stream, format='PNG')
    return base64.b64encode(stream.getvalue())

虽然对REST端点设计一无所知,但我认为更好的解决方案是使用单独的视图声明子资源。假设您的REST模式中有MyCustom资源可由api/mycustom/:id/访问并由MyCustomGet视图提供,例如单独的视图可能负责在api/mycustom/:id/pic/

下提供相应的文件
import django.http

class MyCustomPicView(APIView):
    def get(self, request):
        ...
        image = PIL.Image.open('file/path.png')
        return django.http.HttpResponse(image, content_type='image/png')

答案 1 :(得分:1)

我不确定这是否有用,但这就是我为类似情况所做的。我有一个主模型对象,以及一个我想要标记的半相关对象。

基本上,如果您的CustomClass模型与您需要包含的图像有某种关联,只需直接在序列化程序实例中获取它。

这就是我尝试这样做的方式:

class MyCustomSerializer(serializers.ModelSerializer):
    image_binary = serializers.SerializerMethodField()

    class Meta:
        model = MyCustom
        fields = '__all__'

    def get_image_binary(self, obj):
        return WhateverModel.objects.get(relation=obj).attribute

这只是为模型序列化器添加了一些额外的数据,由序列化器即时计算。您甚至可以为image_binary设置第二个序列化程序,并且在get_image_binary()中只返回序列化程序的.data,就像在视图中一样。

这当然依赖于MyCustom对象以某种方式与图像二进制文件隐式相关的事实。

答案 2 :(得分:1)

首先,在序列化程序中,您提到的模型为java.security.interfaces.RSAPrivateKey,而您的实际型号名称为MyCustom。不知道这是否相关。如果图像是问题,您可以将图像转换为字符串,并将其转换回视图/您想要使用它的任何位置。

CustomClass

将其转换回图像:

class CustomClass:
    obj = None
    image = None

def get_custom():
    r = CustomClass()
    r.obj = MyCustom.objects.all().first()

    import base64

    with open("file/path.png", "rb") as imageFile:
        str_ = base64.b64encode(imageFile.read())
        r.image = str_

    return r

我不知道您的具体用例是什么,但这种结构看起来并不正确。我会使用fh = open("imageToSave.png", "wb") fh.write(r.image.decode('base64')) fh.close() 来存储图像,而在序列化程序中,我只需返回ImageField