feat(fields): migrate from json to orjson for improved performance

migrate field serialization/deserialization to use `orjson` instead of `json` for better performance and ensure compatibility with decryption using `cryptography.fernet`. Handle potential invalid tokens and decoding errors gracefully.
This commit is contained in:
Egor Pavlovich Gorbunov 2026-03-09 16:44:21 +03:00
parent ea158ab2b5
commit f0b92bb475

View file

@ -1,5 +1,5 @@
import json
import orjson
from cryptography.fernet import InvalidToken
from encrypted_fields.fields import EncryptedTextField
@ -18,16 +18,20 @@ class EncryptedJSONTextField(EncryptedTextField):
def get_prep_value(self, value):
if value is not None and not isinstance(value, str):
value = json.dumps(value, default=str)
value = orjson.dumps(value, default=str).decode("utf-8")
return super().get_prep_value(value)
def from_db_value(self, value, expression, connection):
value = super().from_db_value(value, expression, connection)
if value is None:
return None
if isinstance(value, str):
try:
return json.loads(value)
value = self.f.decrypt(value.encode("utf-8")).decode("utf-8")
except (InvalidToken, UnicodeEncodeError):
pass
if isinstance(value, str):
try:
return orjson.loads(value)
except (ValueError, TypeError):
pass
return value
@ -35,9 +39,16 @@ class EncryptedJSONTextField(EncryptedTextField):
def to_python(self, value):
if isinstance(value, (dict, list)):
return value
if value is None:
return value
if isinstance(value, str):
if not hasattr(self, "_already_decrypted"):
try:
value = self.f.decrypt(value.encode("utf-8")).decode("utf-8")
except (InvalidToken, UnicodeEncodeError):
pass
try:
return json.loads(value)
return orjson.loads(value)
except (ValueError, TypeError):
pass
return value