55import uuid
66
77from django .core .exceptions import ValidationError
8- from django .core .files .base import ContentFile
8+ from django .core .files .uploadedfile import SimpleUploadedFile
99from django .contrib .postgres import fields as postgres_fields
1010from django .utils .translation import gettext_lazy as _
1111from psycopg2 .extras import DateRange , DateTimeTZRange , NumericRange
2424from rest_framework .utils import html
2525from drf_extra_fields import compat
2626
27-
2827DEFAULT_CONTENT_TYPE = "application/octet-stream"
2928
3029
3130class Base64FieldMixin (object ):
31+ EMPTY_VALUES = (None , "" , [], (), {})
32+
3233 @property
3334 def ALLOWED_TYPES (self ):
3435 raise NotImplementedError
@@ -41,10 +42,9 @@ def INVALID_FILE_MESSAGE(self):
4142 def INVALID_TYPE_MESSAGE (self ):
4243 raise NotImplementedError
4344
44- EMPTY_VALUES = (None , '' , [], (), {})
45-
4645 def __init__ (self , * args , ** kwargs ):
47- self .represent_in_base64 = kwargs .pop ('represent_in_base64' , False )
46+ self .trust_provided_content_type = kwargs .pop ("trust_provided_content_type" , False )
47+ self .represent_in_base64 = kwargs .pop ("represent_in_base64" , False )
4848 super (Base64FieldMixin , self ).__init__ (* args , ** kwargs )
4949
5050 def to_internal_value (self , base64_data ):
@@ -53,26 +53,39 @@ def to_internal_value(self, base64_data):
5353 return None
5454
5555 if isinstance (base64_data , str ):
56- # Strip base64 header.
57- if ';base64,' in base64_data :
58- header , base64_data = base64_data .split (';base64,' )
56+ file_mime_type = None
57+
58+ # Strip base64 header, get mime_type from base64 header.
59+ if ";base64," in base64_data :
60+ header , base64_data = base64_data .split (";base64," )
61+ if self .trust_provided_content_type :
62+ file_mime_type = header .replace ("data:" , "" )
5963
6064 # Try to decode the file. Return validation error if it fails.
6165 try :
6266 decoded_file = base64 .b64decode (base64_data )
6367 except (TypeError , binascii .Error , ValueError ):
6468 raise ValidationError (self .INVALID_FILE_MESSAGE )
69+
6570 # Generate file name:
6671 file_name = self .get_file_name (decoded_file )
72+
6773 # Get the file name extension:
6874 file_extension = self .get_file_extension (file_name , decoded_file )
75+
6976 if file_extension not in self .ALLOWED_TYPES :
7077 raise ValidationError (self .INVALID_TYPE_MESSAGE )
78+
7179 complete_file_name = file_name + "." + file_extension
72- data = ContentFile (decoded_file , name = complete_file_name )
80+ data = SimpleUploadedFile (
81+ name = complete_file_name ,
82+ content = decoded_file ,
83+ content_type = file_mime_type
84+ )
85+
7386 return super (Base64FieldMixin , self ).to_internal_value (data )
74- raise ValidationError ( _ ( 'Invalid type. This is not an base64 string: {}' . format (
75- type (base64_data ))))
87+
88+ raise ValidationError ( _ ( "Invalid type. This is not an base64 string: {}" . format ( type (base64_data ))))
7689
7790 def get_file_extension (self , filename , decoded_file ):
7891 raise NotImplementedError
@@ -87,10 +100,10 @@ def to_representation(self, file):
87100 # empty base64 str rather than let the exception propagate unhandled
88101 # up into serializers.
89102 if not file :
90- return ''
103+ return ""
91104
92105 try :
93- with open (file .path , 'rb' ) as f :
106+ with open (file .path , "rb" ) as f :
94107 return base64 .b64encode (f .read ()).decode ()
95108 except Exception :
96109 raise IOError ("Error encoding file" )
@@ -156,6 +169,7 @@ class Base64FileField(Base64FieldMixin, FileField):
156169 A django-rest-framework field for handling file-uploads through raw post data.
157170 It uses base64 for en-/decoding the contents of the file.
158171 """
172+
159173 @property
160174 def ALLOWED_TYPES (self ):
161175 raise NotImplementedError ('List allowed file extensions' )
@@ -168,7 +182,6 @@ def get_file_extension(self, filename, decoded_file):
168182
169183
170184class RangeField (DictField ):
171-
172185 range_type = None
173186
174187 default_error_messages = dict (DictField .default_error_messages )
0 commit comments