summaryrefslogtreecommitdiff
path: root/postgresqleu/util/fields.py
diff options
context:
space:
mode:
authorMagnus Hagander2019-08-21 10:58:40 +0000
committerMagnus Hagander2019-08-21 14:30:12 +0000
commit8c78c13fd5ab6b90a03764c35f3d74e4d58410c0 (patch)
tree447307206847d9540d20782d7a4a7e52849060df /postgresqleu/util/fields.py
parentd7d078a501ff3a0e4dd9b1e373570fb242c4c01e (diff)
Add a field+widgets for uploading images into a bytea column
Bypasses the annoying django handling and also doesn't require a special table. PostgreSQL has no problem storing small things inline and toast makes it transparent...
Diffstat (limited to 'postgresqleu/util/fields.py')
-rw-r--r--postgresqleu/util/fields.py54
1 files changed, 54 insertions, 0 deletions
diff --git a/postgresqleu/util/fields.py b/postgresqleu/util/fields.py
index b1ed1190..33d52699 100644
--- a/postgresqleu/util/fields.py
+++ b/postgresqleu/util/fields.py
@@ -1,4 +1,6 @@
from django.db import models
+from django.core.exceptions import ValidationError
+from .forms import ImageBinaryFormField
class LowercaseEmailField(models.EmailField):
@@ -7,3 +9,55 @@ class LowercaseEmailField(models.EmailField):
if value is not None:
value = value.lower()
return value
+
+
+class ImageBinaryField(models.Field):
+ empty_values = [None, b'']
+
+ def __init__(self, *args, **kwargs):
+ ml = kwargs.pop('max_length', None)
+ super(ImageBinaryField, self).__init__(*args, **kwargs)
+ self.max_length = ml
+
+ def deconstruct(self):
+ name, path, args, kwargs = super(ImageBinaryField, self).deconstruct()
+ return name, path, args, kwargs
+
+ def get_internal_type(self):
+ return "ImageBinaryField"
+
+ def get_placeholder(self, value, compiler, connection):
+ return '%s'
+
+ def get_default(self):
+ return b''
+
+ def db_type(self, connection):
+ return 'bytea'
+
+ def get_db_prep_value(self, value, connection, prepared=False):
+ value = super(ImageBinaryField, self).get_db_prep_value(value, connection, prepared)
+ if value is not None:
+ return connection.Database.Binary(value)
+ return value
+
+ def value_to_string(self, obj):
+ """Binary data is serialized as base64"""
+ return b64encode(force_bytes(self.value_from_object(obj))).decode('ascii')
+
+ def to_python(self, value):
+ if self.max_length is not None and len(value) > self.max_length:
+ raise ValidationError("Maximum size of file is {} bytes".format(self.max_length))
+
+ return value
+
+ def save_form_data(self, instance, data):
+ if data is not None:
+ if not data:
+ data = b''
+ setattr(instance, self.name, data)
+
+ def formfield(self, **kwargs):
+ defaults = {'form_class': ImageBinaryFormField}
+ defaults.update(kwargs)
+ return super(ImageBinaryField, self).formfield(**defaults)