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:
parent
ea158ab2b5
commit
f0b92bb475
1 changed files with 17 additions and 6 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import json
|
import orjson
|
||||||
|
from cryptography.fernet import InvalidToken
|
||||||
from encrypted_fields.fields import EncryptedTextField
|
from encrypted_fields.fields import EncryptedTextField
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,16 +18,20 @@ class EncryptedJSONTextField(EncryptedTextField):
|
||||||
|
|
||||||
def get_prep_value(self, value):
|
def get_prep_value(self, value):
|
||||||
if value is not None and not isinstance(value, str):
|
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)
|
return super().get_prep_value(value)
|
||||||
|
|
||||||
def from_db_value(self, value, expression, connection):
|
def from_db_value(self, value, expression, connection):
|
||||||
value = super().from_db_value(value, expression, connection)
|
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
try:
|
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):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
return value
|
return value
|
||||||
|
|
@ -35,9 +39,16 @@ class EncryptedJSONTextField(EncryptedTextField):
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
if isinstance(value, (dict, list)):
|
if isinstance(value, (dict, list)):
|
||||||
return value
|
return value
|
||||||
|
if value is None:
|
||||||
|
return value
|
||||||
if isinstance(value, str):
|
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:
|
try:
|
||||||
return json.loads(value)
|
return orjson.loads(value)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
return value
|
return value
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue