Skip to content

Commit c010ea0

Browse files
authored
Merge pull request #149 from Hipo/enhance-base64-file-field
Enhance Base64FileField
2 parents 480b6b9 + ce1a970 commit c010ea0

File tree

4 files changed

+35
-16
lines changed

4 files changed

+35
-16
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
include README.md
22
include LICENSE
3+
include requirements.txt

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ DRF-EXTRA-FIELDS
33

44
Extra Fields for Django Rest Framework
55

6+
**Possible breaking change in v3.1.0**: In this version we have changed file class used in `Base64FileField` from `ContentFile` to `SimpleUploadedFile` (you may see the change [here](https://github.com/Hipo/drf-extra-fields/pull/149/files#diff-5f77bcb61083cd9c026f6dfb3b77bf8fa824c45e620cdb7826ad713bde7b65f8L72-R85)).
7+
68
[![Build Status](https://travis-ci.org/Hipo/drf-extra-fields.svg?branch=master)](https://travis-ci.org/Hipo/drf-extra-fields)
79
[![codecov](https://codecov.io/gh/Hipo/drf-extra-fields/branch/master/graph/badge.svg)](https://codecov.io/gh/Hipo/drf-extra-fields)
810
[![PyPI Version](https://img.shields.io/pypi/v/drf-extra-fields.svg)](https://pypi.org/project/drf-extra-fields)

drf_extra_fields/fields.py

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import uuid
66

77
from django.core.exceptions import ValidationError
8-
from django.core.files.base import ContentFile
8+
from django.core.files.uploadedfile import SimpleUploadedFile
99
from django.contrib.postgres import fields as postgres_fields
1010
from django.utils.translation import gettext_lazy as _
1111
from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange
@@ -24,11 +24,12 @@
2424
from rest_framework.utils import html
2525
from drf_extra_fields import compat
2626

27-
2827
DEFAULT_CONTENT_TYPE = "application/octet-stream"
2928

3029

3130
class 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

170184
class RangeField(DictField):
171-
172185
range_type = None
173186

174187
default_error_messages = dict(DictField.default_error_messages)

setup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@
44
with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme:
55
README = readme.read()
66

7+
with open(os.path.join(os.path.dirname(__file__), 'requirements.txt')) as requirements_txt:
8+
requirements = requirements_txt.read().strip().splitlines()
9+
710
# allow setup.py to be run from any path
811
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
912

1013
setup(
1114
name='drf-extra-fields',
12-
version='3.0.4',
15+
version='3.1.0',
1316
packages=['drf_extra_fields',
1417
'drf_extra_fields.runtests'],
1518
include_package_data=True,
16-
install_requires=['Django >= 2.2', 'djangorestframework >= 3.9.1'],
1719
extras_require={
1820
"Base64ImageField": ["Pillow >= 6.2.1"],
1921
},
@@ -26,6 +28,7 @@
2628
author_email='pypi@hipolabs.com',
2729
url='https://github.com/Hipo/drf-extra-fields',
2830
python_requires=">=3.5",
31+
install_requires=requirements,
2932
classifiers=[
3033
'Environment :: Web Environment',
3134
'Framework :: Django',

0 commit comments

Comments
 (0)