How to Create a Custom Django Field
Sometimes, you need to extends a django field, perhaps because you need a custom structure data in python, or you need a custom input display in the html template.
In this article, you will create a custom django field, that will save encrypted text and display the decrypted text. Lastly, you also can change the default input display, you can toggle between the text type input and password type input for each field.
You need to understand 2 concepts about it:
- Field The field is only handle how to save something to database, and store it into python memory. So, in our example the
Field
will handle save encrypted string into database, and store decrypted string into python memory - Widget The widget will be responsible for displaying field in the html. And you can guess, that the toggling input type is the
widget
responsibility.
You will use fernet
to encrypt/decrypt your string. Install it using pip install fernet==1.0.1
Here is how do you can use fernet:
from fernet import Fernet
key = Fernet.generate_key()
fernet = Fernet(key)text = "helloworld"
encrypted = fernet.encrypt(text.encode())
decrypted = fernet.decrypt(encrypted)
Field Customization
Here is 2 basic method to override:
get_prep_value
this prepare value to store into databaseto_python
andfrom_db_value
this will do conversion to python object from database
You will inherit from models.CharField
because your custom field just like a CharField with custom modification.
Let’s look at the implementation
class FernetField(models.CharField):
def get_prep_value(self, value):
if not value:
return
return encrypt(value) def from_db_value(self, value, expression, connection):
if not value:
return
return decrypt(value) def to_python(self, value):
if not value:
return
return decrypt(value)
Because it’s a django application, the fernet
‘s key will be stored in the django settings.
and the encrypt
/ decrypt
function looks like
from django.conf import settings
from fernet import Fernet
def get_cipher_suite():
return Fernet(settings.FERNET_KEY.encode())
def encrypt(text):
cipher_suite = get_cipher_suite()
return cipher_suite.encrypt(text.encode()).decode()
def decrypt(text):
cipher_suite = get_cipher_suite()
return cipher_suite.decrypt(text.encode()).decode()
Finally, you can deep dive into the django documentation. It covers all required contexts about field customization.