Model Fields

Django Gentelella Widgets provides custom model fields, form fields, and serializer fields for specialized use cases.

Secure Fields (Encryption)

These fields provide AES encryption for sensitive data stored in the database.

GTEncryptedText

A TextField that automatically encrypts data before saving and decrypts when loading.

from django.db import models
from djgentelella.fields.secure import GTEncryptedText

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    social_security_number = GTEncryptedText(null=True, blank=True)
    private_notes = GTEncryptedText()

Features:

  • Uses AES encryption with EAX mode

  • Derives encryption key from Django’s SECRET_KEY

  • Transparent encryption/decryption on save/load

  • Stores nonce and authentication tag with encrypted data

Warning

Changing your SECRET_KEY will make previously encrypted data unreadable.

GTEncryptedJSONField

A JSONField that encrypts the entire JSON payload before storage.

from django.db import models
from djgentelella.fields.secure import GTEncryptedJSONField

class SecureConfig(models.Model):
    name = models.CharField(max_length=100)
    api_credentials = GTEncryptedJSONField(null=True, blank=True)

Usage:

config = SecureConfig.objects.create(
    name="Payment Gateway",
    api_credentials={
        "api_key": "sk_live_xxxxx",
        "api_secret": "whsec_xxxxx",
        "merchant_id": "12345"
    }
)

# Data is encrypted in database but accessible as dict
print(config.api_credentials['api_key'])  # "sk_live_xxxxx"

Catalog Fields (Filtered Relationships)

These fields extend Django’s relationship fields with built-in queryset filtering.

GTForeignKey

A ForeignKey with automatic queryset filtering based on specified criteria.

from django.db import models
from djgentelella.fields.catalog import GTForeignKey

class Category(models.Model):
    name = models.CharField(max_length=100)
    category_type = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)

class Product(models.Model):
    name = models.CharField(max_length=200)

    # Only show categories where category_type='product' and is_active=True
    category = GTForeignKey(
        Category,
        on_delete=models.CASCADE,
        key_name='category_type',
        key_value='product',
        extra_filters={'is_active': True}
    )

Parameters:

  • key_name - Field name to filter by

  • key_value - Value to match for the filter

  • extra_filters - Dictionary of additional filter conditions

GTOneToOneField

OneToOne relationship with the same filtering capabilities as GTForeignKey.

from djgentelella.fields.catalog import GTOneToOneField

class UserSettings(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

    # Link to a specific config type
    config = GTOneToOneField(
        Configuration,
        on_delete=models.SET_NULL,
        null=True,
        key_name='config_type',
        key_value='user_settings'
    )

GTManyToManyField

ManyToMany relationship with queryset filtering.

from djgentelella.fields.catalog import GTManyToManyField

class Article(models.Model):
    title = models.CharField(max_length=200)

    # Only show active tags in forms
    tags = GTManyToManyField(
        Tag,
        key_name='is_active',
        key_value=True,
        blank=True
    )

Tree Fields

Form fields for working with tree-structured data, built on django-tree-queries. The model must inherit from tree_queries.models.TreeNode.

Each option is rendered indented by its depth in the tree: the option gets a l<depth> CSS class, and options on a disabled level are rendered as disabled. The fields default to the TreeSelect / TreeSelectMultiple widgets, which provide the templates doing that.

Note

The depth comes from tree_depth, which django-tree-queries only annotates on querysets that went through with_tree_fields(). The fields call it for you, so a plain Model.objects.all() is fine.

GentelellaTreeNodeChoiceField

A select field for choosing a single node from a tree structure.

from django import forms
from djgentelella.fields.tree import GentelellaTreeNodeChoiceField
from myapp.models import Category  # inherits from TreeNode

class ProductForm(forms.Form):
    category = GentelellaTreeNodeChoiceField(
        queryset=Category.objects.all(),
        disable0=True,  # Disable root level (level 0)
        disable1=False,  # Enable level 1
        disable2=False,  # Enable level 2
    )

Parameters:

  • disable0, disable1, disable2, … - Disable selection for the given tree level. Any depth is accepted, and only a truthy value disables the level, so disable1=False leaves level 1 selectable.

GentelellaTreeNodeMultipleChoiceField

Multi-select version for choosing multiple tree nodes.

from djgentelella.fields.tree import GentelellaTreeNodeMultipleChoiceField

class ArticleForm(forms.Form):
    categories = GentelellaTreeNodeMultipleChoiceField(
        queryset=Category.objects.all(),
        disable0=True,  # Can't select root categories
    )

DRF Serializer Fields

Custom Django REST Framework fields for file handling.

GTBase64FileField

Handles file uploads from base64-encoded data in API requests.

from rest_framework import serializers
from djgentelella.fields.files import GTBase64FileField

class DocumentSerializer(serializers.ModelSerializer):
    file = GTBase64FileField(max_files=5, delete_if_empty=False)

    class Meta:
        model = Document
        fields = ['id', 'name', 'file']

Request format:

{
    "name": "My Document",
    "file": [
        {
            "name": "document.pdf",
            "value": "JVBERi0xLjQKJe..."
        }
    ]
}

Parameters:

  • max_files - Maximum number of files allowed (default: 1)

  • delete_if_empty - Delete existing file if empty submission (default: True)

ChunkedFileField

Handles resumable/chunked file uploads for large files.

from rest_framework import serializers
from djgentelella.fields.files import ChunkedFileField

class LargeFileSerializer(serializers.ModelSerializer):
    file = ChunkedFileField()

    class Meta:
        model = LargeFile
        fields = ['id', 'name', 'file']

Features:

  • Integrates with djgentelella.chunked_upload module

  • Supports resumable uploads

  • Handles upload tokens and metadata

DigitalSignatureField

Handles digital signature file uploads with Firmador Libre integration.

from rest_framework import serializers
from djgentelella.fields.files import DigitalSignatureField

class SignedDocumentSerializer(serializers.ModelSerializer):
    signature_file = DigitalSignatureField()

    class Meta:
        model = SignedDocument
        fields = ['id', 'document', 'signature_file']

Date/Time Serializer Fields

Custom DRF fields that handle empty strings gracefully.

GTDateField

DateField that accepts empty strings without validation errors.

from rest_framework import serializers
from djgentelella.serializers import GTDateField

class PersonSerializer(serializers.ModelSerializer):
    birth_date = GTDateField(allow_empty_str=True)

    class Meta:
        model = Person
        fields = ['name', 'birth_date']

GTDateTimeField

DateTimeField that accepts empty strings without validation errors.

from djgentelella.serializers import GTDateTimeField

class EventSerializer(serializers.ModelSerializer):
    start_time = GTDateTimeField(allow_empty_str=True)
    end_time = GTDateTimeField(allow_empty_str=True)

    class Meta:
        model = Event
        fields = ['title', 'start_time', 'end_time']

Note

These fields are especially useful with DataTables where empty filter values are sent as empty strings.

Date Range Form Widgets

Widgets for selecting date ranges in forms.

DateRangeTextWidget

Text input that parses date range in “start - end” format.

from django import forms
from django_filters import FilterSet, DateFromToRangeFilter
from djgentelella.fields.drfdatetime import DateRangeTextWidget

class EventFilterSet(FilterSet):
    date_range = DateFromToRangeFilter(
        widget=DateRangeTextWidget(attrs={'placeholder': 'YYYY-MM-DD'})
    )

    class Meta:
        model = Event
        fields = ['date_range']

DateTimeRangeTextWidget

Similar widget for datetime ranges including time component.

from djgentelella.fields.drfdatetime import DateTimeRangeTextWidget

class LogFilterSet(FilterSet):
    timestamp_range = DateTimeFromToRangeFilter(
        widget=DateTimeRangeTextWidget(
            attrs={'placeholder': 'YYYY-MM-DD HH:MM:SS'}
        )
    )

API Reference

Secure Fields

class djgentelella.fields.secure.GTEncryptedJSONField(verbose_name=None, name=None, encoder=None, decoder=None, **kwargs)

Encrypt data using AES and secure django key use in models can store JSON objects: in models.py

class MyModel(models.Model):

my_secret = GTEncryptedJSONField(null=True, blank=True)

get_prep_value(value)

Perform preliminary non-db specific value checks and conversions.

class djgentelella.fields.secure.GTEncryptedText(*args, db_collation=None, **kwargs)

Encrypt data using AES and secure django key use in models like: in models.py

class MyModel(models.Model):

my_secret = GTEncryptedText(null=True, blank=True)

pre_save(model_instance, add)

Return field’s value just before saving.

value_from_object(obj)

Return the value of this field in the given model instance.

Catalog Fields

class djgentelella.fields.catalog.GTForeignKey(*args, **kwargs)
formfield(*, using=None, **kwargs)

Pass limit_choices_to to the field being constructed.

Only passes it if there is a type that supports related fields. This is a similar strategy used to pass the queryset to the field being constructed.

class djgentelella.fields.catalog.GTManyToManyField(*args, **kwargs)
formfield(*, using=None, **kwargs)

Pass limit_choices_to to the field being constructed.

Only passes it if there is a type that supports related fields. This is a similar strategy used to pass the queryset to the field being constructed.

class djgentelella.fields.catalog.GTOneToOneField(*args, **kwargs)

Tree Fields

Form fields for tree structured models, built on django-tree-queries.

django-tree-queries only annotates tree_depth on querysets that went through with_tree_fields(), so these fields request it themselves and callers can pass a plain queryset.

The labels are dicts rather than strings because gentelella/widgets/tree_select_option.html reads label.level, label.disable and label.text to indent and disable the options.

class djgentelella.fields.tree.GentelellaTreeNodeChoiceField(queryset, *args, **kwargs)

Select one node, each option indented by its depth in the tree.

class djgentelella.fields.tree.GentelellaTreeNodeMultipleChoiceField(queryset, *args, **kwargs)

Select several nodes, each option indented by its depth in the tree.

class djgentelella.fields.tree.TreeNodeChoiceMixin(queryset, *args, **kwargs)

Turns each option label into the dict the tree option template expects.

djgentelella.fields.tree.pop_disabled_levels(kwargs)

Read disable0, disable1, … out of kwargs.

A level is disabled only when its value is truthy, so disable1=False leaves level 1 selectable.

djgentelella.fields.tree.with_tree_fields(queryset)

Ask django-tree-queries for tree_depth, when the queryset supports it.

File Fields