Created
January 22, 2019 17:40
-
-
Save tomfa/2040e8158c1c095852ba05ba226c7b38 to your computer and use it in GitHub Desktop.
Django CompressedJSONField
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.utils.text import compress_string | |
from django.core.serializers.json import DjangoJSONEncoder | |
class CompressedBinaryField(models.BinaryField): | |
compress = compress_string | |
@staticmethod | |
def uncompress(s): | |
zbuf = io.BytesIO(s) | |
zfile = gzip.GzipFile(fileobj=zbuf) | |
ret = zfile.read() | |
zfile.close() | |
return ret | |
def get_db_prep_save(self, value, connection=None, prepared=False): | |
if value is not None and prepared is False: | |
value = CompressedBinaryField.compress(value) | |
return models.BinaryField.get_db_prep_save(self, value, connection) | |
def is_binary(self, value): | |
return value and (type(value) == bytes or isinstance(value, memoryview)) | |
def _get_val_from_obj(self, obj): | |
val = obj and getattr(obj, self.attname) | |
if self.is_binary(val): | |
return CompressedBinaryField.uncompress(val) | |
if val is None: | |
return self.get_default() | |
return val | |
def post_init(self, instance=None, **kwargs): | |
value = self._get_val_from_obj(instance) | |
setattr(instance, self.attname, value) | |
def contribute_to_class(self, cls, name, private_only=False): | |
super(CompressedBinaryField, self).contribute_to_class(cls, name) | |
models.signals.post_init.connect(self.post_init, sender=cls) | |
def get_internal_type(self): | |
return 'BinaryField' | |
class CompressedJSONField(CompressedBinaryField): | |
encoder = DjangoJSONEncoder | |
def __init__(self, *args, **kwargs): | |
self.encoder = kwargs.pop('encoder', OtovoJsonEncoder) | |
super().__init__(*args, **kwargs) | |
def get_db_prep_save(self, value, connection=None, prepared=False): | |
if value is not None and prepared is False: | |
value = json.dumps(value, cls=self.encoder).encode('utf-8') | |
return super().get_db_prep_save(value, connection, prepared) | |
def _get_val_from_obj(self, obj): | |
if obj: | |
val = super()._get_val_from_obj(obj) | |
if self.is_binary(val): | |
return json.loads(val.decode('utf-8')) | |
return val | |
else: | |
return self.get_default() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from fields import CompressedJSONField | |
class MyModel(models.Model): | |
price_points = CompressedJSONField( | |
null=True, | |
help_text='Accepts JSON, and stores compressed in database', | |
# encoder=MyCustomJSONEncoder | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey @tomfa ! Hope you are doing well.
We used you field but within time we noticed a bug that was provoked with a field. So I have made my own version. Changes:
I would advise everyone who is reading this and willing to use, please use my fork.https://gist.github.com/cddumanov/682d96b49f49ddef02ffc4552b0fbe0e