无法在django rest框架中上传图像并获得预期的行为

时间:2018-05-28 16:50:41

标签: python django django-models django-rest-framework django-serializer

在过去的两天里,我已经尝试了所有可能的选项,似乎没有任何效果。请耐心等待,这将有点长。

这是我的UserProfile模型

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE, )
    status = models.CharField(max_length=255, null=True, blank=True)
    thumbnail = models.ImageField(upload_to='media/user/', blank=True, null=True)

这是Serializer,

class UserProfileSerializer(serializers.ModelSerializer):
    thumbnail = serializers.ImageField(max_length=256, use_url=True, allow_empty_file=False)

    class Meta:
        model = models.UserProfile
        fields = ('status', 'thumbnail',)

现在,当我尝试使用POSTMAN上传此图像时,这是我得到的输出,

{
    "thumbnail": [
        "No file was submitted."
    ]
}

阅读一些SO帖子我尝试将默认的serializer.ImageField替换为此,

class Base64ImageField(serializers.ImageField):
    """
    A Django REST framework field for handling image-uploads through raw post data.
    It uses base64 for encoding and decoding the contents of the file.

    Heavily based on
    https://github.com/tomchristie/django-rest-framework/pull/1268

    Updated for Django REST framework 3.
    """

    def to_internal_value(self, data):

        # Check if this is a base64 string
        if isinstance(data, six.string_types):
            # Check if the base64 string is in the "data:" format
            if 'data:' in data and ';base64,' in data:
                # Break out the header from the base64 content
                header, data = data.split(';base64,')

            # Try to decode the file. Return validation error if it fails.
            try:
                decoded_file = base64.b64decode(data)
            except TypeError:
                self.fail('invalid_image')

            # Generate file name:
            file_name = str(uuid.uuid4())[:12]  # 12 characters are more than enough.
            # Get the file name extension:
            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

没有任何改变,我继续得到完全相同的行为。我期待的输出是这样的。

{
  "status":"something",
  "thumbnail":"file/path"
}

这就是我使用POSTMAN上传图片的方式。

enter image description here

有人可以帮我解决这个问题吗,我几乎尝试了SO上的所有选项都无济于事。

2 个答案:

答案 0 :(得分:2)

您应该通过邮递员发送base64编码的图像数据(不是文件上传)(如果您使用的是Base64ImageField)

您也可以参考:Error uploading image using postman in django rest framework

How to send a base64 image in postman

获取编码图像的过程

  1. 使用Image encoder进行图像编码。上传图像后,您可以选择复制图像。
  2. 复制数据并将其粘贴到.txt文件
  3. 您将获得一个前缀为'数据的字符串:image / png; base64,'
  4. 从字符串中删除该前缀并将整个字符串粘贴到POSTMAN中

答案 1 :(得分:2)

我建议使用multipart / form-data上传图像以及其他json数据,如下所示:

# create a custom image field with additional constraints e.g. size of the image
class ConstrainedImageField(ImageField):
    MAX_SIZE = 2000000  # in Bytes
    default_error_messages = {
        'image_size': _('The size of the image is {image_size} KB. The maximum size allowed is: {max_size} KB.'),
    }

    def to_internal_value(self, data):
        super(ConstrainedImageField, self).to_internal_value(data=data)
        file_size = data.size
        if file_size > self.MAX_SIZE:
            max_size_kb = self.MAX_SIZE/1000
            file_size_kb = file_size/1000
            self.fail('image_size', max_size=max_size_kb, image_size=file_size_kb)



class UserProfileSerializer(serializers.ModelSerializer):
    thumbnail = serializers.ConstrainedImageField(max_length=256, use_url=True, allow_empty_file=False)

    class Meta:
        model = models.UserProfile
        fields = ('status', 'thumbnail',)

    def validate(self, data):
        # ..
        # ..

        # get the image data from request.FILES:
        self.context["thumbnail"] = self.context['request'].FILES.get("thumbnail")
        return data

    def create(self, validated_data):
        # set the thumbnail field:
        validated_data['thumbnail'] = self.context.get("thumbnail")
        user_profile = UserProfile.objects.create(**validated_data)
        return user_profile