How to Create a Custom Django Field

Muhammad Ihfazhillah
2 min readOct 18, 2021

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 database
  • to_python and from_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.

--

--

Muhammad Ihfazhillah

Teacher, freelancer software developer. Mainly code using python for scraping and web development.