Solución:
Creo que el problema es que to_python también se llama cuando asigna un valor a su campo personalizado (como parte de la validación puede ser, según este enlace). Entonces, el problema es distinguir entre las llamadas to_python en las siguientes situaciones:
- Cuando Django asigna un valor de la base de datos al campo (ahí es cuando desea descifrar el valor)
- Cuando asigna manualmente un valor al campo personalizado, por ejemplo, record.field = value
Un truco que podría usar es agregar un prefijo o sufijo a la cadena de valor y verificar eso en lugar de hacer isinstance cheque.
Iba a escribir un ejemplo, pero encontré este (incluso mejor :)).
Cheque BaseEncryptedField: https://github.com/django-extensions/django-extensions/blob/2.2.9/django_extensions/db/fields/encrypted.py (enlace a una versión anterior porque el campo se eliminó en 3.0.0; consulte el problema # 1359 por motivo de desaprobación)
Fuente: Campo personalizado de Django: ¿ejecutar solo to_python () en valores de la base de datos?
Deberías estar anulando to_python
, como lo hizo el fragmento.
Si echa un vistazo a la CharField
clase, puedes ver que no tiene una value_to_string
método:
django/db/models/fields/__init__.py
Los docs dicen que el to_python
El método debe lidiar con tres cosas:
- Una instancia del tipo correcto
- Una cadena (por ejemplo, de un deserializador).
- Lo que sea que devuelva la base de datos para el tipo de columna que está utilizando.
Actualmente solo se ocupa del tercer caso.
Una forma de manejar esto es crear una clase especial para una cadena descifrada:
class DecryptedString(str):
pass
Entonces puedes detectar esta clase y manejarla en to_python()
:
def to_python(self, value):
if isinstance(value, DecryptedString):
return value
decrypted = self.encrypter.decrypt(encrypted)
return DecryptedString(decrypted)
Esto le impide descifrar más de una vez.
Olvidó configurar la metaclase:
class EncryptedCharField(models.CharField):
__metaclass__ = models.SubfieldBase
La documentación de campos personalizados explica por qué esto es necesario.