使用Django / django-rest-framework中的ModelSerializers上传base64图像

时间:2015-07-29 03:58:17

标签: django django-rest-framework

我正在尝试使用AngularJS上传图片。

我的模型如下:

class Profile(models.Model):
    user = models.OneToOneField(User)
    name = models.CharField(max_length=20)
    profile_picture = ImageField(upload_to=settings.MEDIA_ROOT, blank=True)

我有序列化器:

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile

我有以下观点:

class ProfileViewSet(viewsets.ModelViewSet):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializers

我的帖子转储就像:

name: "David"
user: 1
profile_picture: ""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…917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de6//U36fYf6Z697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuv/1d+n2H+meve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r/9bfp9h/pnr3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de6//Z""

但是,这对我来说是400 BAD REQUEST错误。错误消息是:

{"profile_picture":["The submitted data was not a file. Check the encoding type on the form."]}

2 个答案:

答案 0 :(得分:3)

对应的序列化器如下:

from rest_framework import serializers
from .models import Profile     

class Base64ImageField(serializers.ImageField):

    def to_internal_value(self, data):
        from django.core.files.base import ContentFile
        import base64
        import six
        import uuid

        if isinstance(data, six.string_types):
            if 'data:' in data and ';base64,' in data:
                header, data = data.split(';base64,')

            try:
                decoded_file = base64.b64decode(data)
            except TypeError:
                self.fail('invalid_image')

            file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
            file_extension = self.get_file_extension(file_name, decoded_file)
            complete_file_name = "%s.%s" % (file_name, file_extension, )
            data = ContentFile(decoded_file, name=complete_file_name)

        return super(Base64ImageField, self).to_internal_value(data)

    def get_file_extension(self, file_name, decoded_file):
        import imghdr

        extension = imghdr.what(file_name, decoded_file)
        extension = "jpg" if extension == "jpeg" else extension

        return extension

class PhotoSerializer(serializers.ModelSerializer):
    profile_picture = Base64ImageField(max_length=None, use_url=True)

    class Meta:
       model = Profile
       fields = ('profile_picture',)

答案 1 :(得分:1)

您是否为上传指定了内容类型? 'multipart / form-data'?您可能需要在视图上指定MultiPartParser以接受文件上传。

from rest_framework.parsers import JSONParser, MultiPartParser

class ProfileViewSet(viewsets.ModelViewSet):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializers
    parser_classes = (MultiPartParser, JSONParser)

在serializers.py

import base64

from django.core.files.base import ContentFile
from rest_framework import serializers

# From  gist.github.com/yprez/7704036
class Base64ImageField(serializers.ImageField):
    def from_native(self, data):
        if isinstance(data, basestring) and data.startswith('data:image'):
            # base64 encoded image - decode
            format, imgstr = data.split(';base64,')  # format ~= data:image/X,
            ext = format.split('/')[-1]  # guess file extension

            data = ContentFile(base64.b64decode(imgstr), name='temp.' + ext)

        return super(Base64ImageField, self).from_native(data)


class ProfileSerializer(serializers.ModelSerializer):
    profile_picture =  Base64ImageField()

    class Meta:
        model = Profile
        fields = ('profile_picture',)