Django Encrypted Model Fields

0.6.5 · active · verified Thu Apr 16

django-encrypted-model-fields provides a set of Django model fields that encrypt data before saving it to the database, leveraging the robust `cryptography` library. It's currently at version 0.6.5 and typically follows Django's release cycle for compatibility, with more frequent updates for bug fixes or features. It ensures data at rest is protected.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates defining a Django model with `EncryptedCharField` and `EncryptedTextField`. It highlights the critical `ENCRYPTED_FIELD_KEYS` setting in `settings.py`, which maps key names to their actual encryption keys. Data saved using these fields will be automatically encrypted and decrypted on access. Note the use of `os.environ.get` for secure key management. The standalone script includes a simplified Django setup for immediate execution (requires `Django` to be installed), but in a real project, you'd integrate the models into your existing Django application and manage migrations via `manage.py`.

import os
from django.conf import settings
from django.db import models

# Minimal Django settings for standalone script testing
if not settings.configured:
    settings.configure(
        DEBUG=True,
        INSTALLED_APPS=[
            'encrypted_model_fields' # Required for migrations/field registration
        ],
        DATABASES={
            'default': {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': ':memory:',
            }
        },
        # CRUCIAL: Define encryption keys
        ENCRYPTED_FIELD_KEYS={
            'default': os.environ.get('ENCRYPTED_FIELD_DEFAULT_KEY', 'a_secret_key_for_dev_or_testing_ONLY_do_not_use_in_prod'),
            'billing': os.environ.get('ENCRYPTED_FIELD_BILLING_KEY', 'another_key_for_billing_data')
        },
        # Required for any Django project
        SECRET_KEY='django-insecure-testkey-very-insecure'
    )

# Ensure apps are loaded (needed for standalone scripts)
import django
django.setup()

from encrypted_model_fields.fields import EncryptedCharField, EncryptedTextField

class Customer(models.Model):
    name = models.CharField(max_length=100)
    email = EncryptedCharField(max_length=255)
    notes = EncryptedTextField(blank=True, null=True, key_name='billing') # Use a specific key

    def __str__(self):
        return self.name

# Example usage (requires database setup, e.g., via manage.py migrate)
if __name__ == '__main__':
    # This part would typically be in a Django shell or view
    print("--- Quickstart Example ---")

    # In a real Django project, you'd run 'python manage.py makemigrations' and 'python manage.py migrate'
    # For this standalone script, we'll simulate migrations for Customer model
    from django.apps import apps
    from django.core.management.commands import makemigrations, migrate
    from io import StringIO

    # Simulate makemigrations
    # Note: This is a hack for a standalone script, not for production use.
    # In a real project, 'encrypted_model_fields' would be in INSTALLED_APPS and 'python manage.py makemigrations/migrate' would be run.

    # Create a simple fake app for the model
    class FakeAppConfig(apps.AppConfig):
        name = 'my_app'
        verbose_name = 'My App'

    apps.apps_ready = False # Reset app loading for standalone execution
    apps.clear_cache()
    apps.set_available_apps(['my_app'])
    apps.populate(settings.INSTALLED_APPS + ['my_app'])
    settings.INSTALLED_APPS += ['my_app']
    apps.get_app_config('my_app').models = {'customer': Customer}

    # For real migration, save models.py in an app and run commands.
    # For this quickstart, we'll just interact with the model directly in memory after setup.

    # Create a record
    customer = Customer.objects.create(name='Alice', email='alice@example.com', notes='Confidential billing info.')
    print(f"Created customer: {customer.name}")
    print(f"Stored email (encrypted): {customer.email}") # Will show encrypted value if accessed directly before decrypt

    # Retrieve and decrypt
    retrieved_customer = Customer.objects.get(name='Alice')
    print(f"Retrieved email (decrypted): {retrieved_customer.email}")
    print(f"Retrieved notes (decrypted): {retrieved_customer.notes}")

    # Update
    retrieved_customer.email = 'alice.smith@example.com'
    retrieved_customer.save()
    print(f"Updated email: {Customer.objects.get(name='Alice').email}")

view raw JSON →