How to add a custom editable field in the django admin and then transform it before storing it in a field in the model?
Given this Model:
import json
from django.db import models
from django.core.serializers.json import DjangoJSONEncoder
class Foo(models.Model):
_encrypted_data = models.TextField(null=True, blank=True)
@property
def data(self):
encrypted = self._encrypted_data
if not encrypted:
return {}
return json.loads(decrypt(encrypted))
@data.setter
def data(self, value):
if not value:
self._encrypted_data = {}
return
self._encrypted_data = encrypt(
json.dumps(value, cls=DjangoJSONEncoder)
)
The field Model._encrypted_data
contains encrypted data.
The property Model.data
makes it easy to work with the decrypted data in the code: encrypt/decrypt automatically.
I am looking for an editable admin field that represents the Model.data
property.
I started to explore a custom Admin Form but I am not sure how to pass the decrypted data to the field and then save it on the model.
class FooAdminForm(forms.ModelForm):
class Meta:
model = Foo
fields = '__all__'
data = forms.JSONField(label='Data', required=False)
class FooAdmin(admin.ModelAdmin):
form = FooAdminForm
You can define a custom model field, for example by subclassing a TextField
:
# app_name/fields.py
class EncryptedJsonField(models.TextField):
def to_python(self, value):
value = super().to_python(value)
if not value:
return {}
return json.loads(decrypt(value))
def from_db_value(self, value, expression, connection):
value = super().from_db_value(value, expression, connection)
if not value:
return {}
return json.loads(decrypt(value))
def get_db_prep_value(self, value, connection, prepared=False):
if value:
value = encrypt(json.dumps(value, cls=DjangoJSONEncoder))
return super().get_db_prep_value(value, connection, prepared)
and in the model use this as:
class Foo(models.Model):
data = EncryptedJsoNField()