django-cryptography
django-cryptography copied to clipboard
Json fields
This doesn't work for Json fields... can you propose a solution?
Do you have an example of anything you've tried?
Just off the top of my head I would consider using a CharField
or TextField
and treating the json as a long string (which it is, basically).
was able to get it working
encrypt(JSONWrappedTextField)
class JSONWrappedTextField(models.TextField):
def to_python(self, value):
if isinstance(value, six.string_types):
value = super(JSONWrappedTextField, self).to_python(value)
value = json.loads(value)
return value
def get_db_prep_value(self, value, connection, prepared=False):
value = super(JSONWrappedTextField, self).get_db_prep_value(value, connection, prepared)
if isinstance(value, dict):
value = json.dumps(value)
return value
Thanks a lot @harry-kim this is just what I needed! If using python 3 I believe you can just do:
encrypt(JSONWrappedTextField)
class JSONWrappedTextField(models.TextField):
def to_python(self, value):
if isinstance(value, str): #changed this line
value = super(JSONWrappedTextField, self).to_python(value)
value = json.loads(value)
return value
def get_db_prep_value(self, value, connection, prepared=False):
value = super(JSONWrappedTextField, self).get_db_prep_value(value, connection, prepared)
if isinstance(value, dict):
value = json.dumps(value)
return value
Update: I don't think this works if you already have existing JSONfield objects. I started getting weird string escaping errors.
The other issue is default values, I am getting this on migration:
django.db.utils.ProgrammingError: column "remote" is of type jsonb but default expression is of type bytea
Code:
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib.postgres.fields import JSONField
from django_cryptography.fields import encrypt
class Repo(models.Model):
# ...
remote = encrypt(JSONField(default=dict, encoder=DjangoJSONEncoder))
Looks like the issue is that JSONField
overwrites .db_type()
method and EncryptedMixin
does not. This monkey-patch fixed it for me:
EncryptedMixin.db_type = models.Field.db_type
I faced with the same issue! The @Suor tip could do the tricks!
However just in case, an another alternative could be to use PickledField instead:
from django.db import models
from django_cryptography.fields import encrypt, PickledField
class Foo(models.Model):
extra_data = encrypt(PickledField(default=dict))
In any case, data must be store in Bytea data type (encrypted string). So using JSONField or even HStoreField doesn't make sense : you won't be able to encrypt data and take power of SGBD functions with JSON or HStore. You could just store a byte string! This is why @Suor override the base field data type (db_type).
After all, you probably just needs to serializer/deserializer dict/list data into code, not in DB!
This isn't working for
Thanks a lot @harry-kim this is just what I needed! If using python 3 I believe you can just do:
encrypt(JSONWrappedTextField) class JSONWrappedTextField(models.TextField): def to_python(self, value): if isinstance(value, str): #changed this line value = super(JSONWrappedTextField, self).to_python(value) value = json.loads(value) return value def get_db_prep_value(self, value, connection, prepared=False): value = super(JSONWrappedTextField, self).get_db_prep_value(value, connection, prepared) if isinstance(value, dict): value = json.dumps(value) return value
This isn't working for me. The to_python code is never called. From examining the EncryptedMixin the only callback I see that would work is get_prep_value or get_db_prep_value
I get a String back but have no way to convert it to JSON.
Here is what I got working. Notice I had to override the get_db_converters, so there is a chance to turn the decrypted string back to JSON.
NOTE: DJANGO 4.2
class JSONWrappedTextField(JSONField):
def get_db_converters(self, connection):
"""Override to we can call our converter"""
return [self.my_from_db_value]
def my_from_db_value(self, value, expression, connection):
"""Once read from the DB get the decrypted Str and turn it into JSON"""
value = self.from_db_value(value, expression, connection)
if value is not None:
value = self.to_python(value)
return value
Looks like the issue is that
JSONField
overwrites.db_type()
method andEncryptedMixin
does not. This monkey-patch fixed it for me:EncryptedMixin.db_type = models.Field.db_type
where will this go? in settings file?