diff options
author | Magnus Hagander | 2019-08-21 10:58:40 +0000 |
---|---|---|
committer | Magnus Hagander | 2019-08-21 14:30:12 +0000 |
commit | 8c78c13fd5ab6b90a03764c35f3d74e4d58410c0 (patch) | |
tree | 447307206847d9540d20782d7a4a7e52849060df /postgresqleu/util/fields.py | |
parent | d7d078a501ff3a0e4dd9b1e373570fb242c4c01e (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.py | 54 |
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) |