Skip to content

Instantly share code, notes, and snippets.

@dalmarcogd
Last active September 11, 2022 11:16
Show Gist options
  • Select an option

  • Save dalmarcogd/14cdf85b79bfda6aa0db155badf1c1cb to your computer and use it in GitHub Desktop.

Select an option

Save dalmarcogd/14cdf85b79bfda6aa0db155badf1c1cb to your computer and use it in GitHub Desktop.
Upload file in python with base64 and json.
import base64
import binascii
import uuid
from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile
from django.utils import six
from django.utils.translation import ugettext_lazy as _
from rest_framework.fields import (
DateField,
DateTimeField,
DictField,
FileField,
FloatField,
ImageField,
IntegerField,
)
from django.conf import settings
class Base64FieldMixin(object):
ALLOWED_TYPES = NotImplemented
INVALID_FILE_MESSAGE = NotImplemented
INVALID_TYPE_MESSAGE = NotImplemented
EMPTY_VALUES = (None, '', [], (), {})
def __init__(self, *args, **kwargs):
self.represent_in_base64 = kwargs.pop('represent_in_base64', False)
super(Base64FieldMixin, self).__init__(*args, **kwargs)
def to_internal_value(self, base64_data):
# Check if this is a base64 string
if base64_data in self.EMPTY_VALUES:
return None
if isinstance(base64_data, six.string_types):
# Strip base64 header.
if ';base64,' in base64_data:
header, base64_data = base64_data.split(';base64,')
# Try to decode the file. Return validation error if it fails.
try:
decoded_file = base64.b64decode(base64_data)
except (TypeError, binascii.Error, ValueError):
raise ValidationError(self.INVALID_FILE_MESSAGE)
# Generate file name:
# 12 characters are more than enough.
file_name = str(uuid.uuid4())[:12]
# Get the file name extension:
file_extension = self.get_file_extension(file_name, decoded_file)
if file_extension not in self.ALLOWED_TYPES:
raise ValidationError(self.INVALID_TYPE_MESSAGE)
complete_file_name = file_name + "." + file_extension
data = ContentFile(decoded_file, name=complete_file_name)
return super(Base64FieldMixin, self).to_internal_value(data)
raise ValidationError(_('This is not an base64 string'))
def get_file_extension(self, filename, decoded_file):
raise NotImplemented
def to_representation(self, file):
if self.represent_in_base64:
try:
with open(file.path, 'rb') as f:
return base64.b64encode(f.read()).decode()
except Exception as e:
print 'Fails to decode file: %s (%s)' % (e.message, type(e))
else:
return super(Base64FieldMixin, self).to_representation(file)
import imghdr
from django.utils.translation import ugettext_lazy as _
from rest_framework.fields import FileField
from .base64_mixin_field import Base64FieldMixin
class Base64FileField(Base64FieldMixin, FileField):
"""
A django-rest-framework field for handling file-uploads through raw post data.
It uses base64 for en-/decoding the contents of the file.
"""
ALLOWED_TYPES = (
"jpeg",
"jpg",
"png",
"gif",
"txt",
"csv"
)
INVALID_FILE_MESSAGE = _("Please upload a valid file.")
INVALID_TYPE_MESSAGE = _("The type of the file couldn't be determined.")
def get_file_extension(self, filename, decoded_file):
return imghdr.what(filename, decoded_file)
from rest_framework.fields import ImageField
from django.core.exceptions import ValidationError
from .base64_mixin_field import Base64FieldMixin
from .image_base64_field import Base64ImageField
class HybridImageField(Base64ImageField):
"""
A django-rest-framework field for handling image-uploads through
raw post data, with a fallback to multipart form data.
"""
def to_internal_value(self, data):
"""
Try Base64Field first, and then try the ImageField
``to_internal_value``, MRO doesn't work here because
Base64FieldMixin throws before ImageField can run.
"""
try:
return Base64FieldMixin.to_internal_value(self, data)
except ValidationError:
return ImageField.to_internal_value(self, data)
import imghdr
from rest_framework.fields import ImageField
from django.utils.translation import ugettext_lazy as _
from .base64_mixin_field import Base64FieldMixin
class Base64ImageField(Base64FieldMixin, ImageField):
"""
A django-rest-framework field for handling image-uploads through raw post data.
It uses base64 for en-/decoding the contents of the file.
"""
ALLOWED_TYPES = (
"jpeg",
"jpg",
"png",
"gif"
)
INVALID_FILE_MESSAGE = _("Please upload a valid image.")
INVALID_TYPE_MESSAGE = _("The type of the image couldn't be determined.")
def get_file_extension(self, filename, decoded_file):
extension = imghdr.what(filename, decoded_file)
extension = "jpg" if extension == "jpeg" else extension
return extension
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment