Configuration Reference

All django-tenant-options settings are configured through a single dictionary in your Django settings.py:

DJANGO_TENANT_OPTIONS = {
    "TENANT_MODEL": "yourapp.Tenant",
    # ... other settings
}

Individual models can override most settings by setting the corresponding class attribute directly.

Required settings

TENANT_MODEL

Type

str

Default

"django_tenant_options.Tenant"

Required

Yes

The dotted path to your tenant model. This is the only setting you must configure.

DJANGO_TENANT_OPTIONS = {
    "TENANT_MODEL": "myapp.Tenant",
}

Tenant relationship settings

TENANT_ON_DELETE

Type

Django on_delete action

Default

models.CASCADE

What happens to Options and Selections when a related Tenant is deleted. Uses Django’s standard on_delete arguments.

from django.db import models

DJANGO_TENANT_OPTIONS = {
    "TENANT_ON_DELETE": models.CASCADE,  # or models.PROTECT, models.SET_NULL, etc.
}

Option relationship settings

OPTION_ON_DELETE

Type

Django on_delete action

Default

models.CASCADE

What happens to Selections when a related Option is deleted. Since Options use soft deletes by default, this setting is rarely triggered.

Base class settings

These settings let you replace the default Django base classes with custom ones (e.g., from django-auto-prefetch). Values can be class references or dotted string paths.

MODEL_CLASS

Type

class or str

Default

django.db.models.Model

MANAGER_CLASS

Type

class or str

Default

django.db.models.Manager

QUERYSET_CLASS

Type

class or str

Default

django.db.models.QuerySet

FOREIGNKEY_CLASS

Type

class or str

Default

django.db.models.ForeignKey

ONETOONEFIELD_CLASS

Type

class or str

Default

django.db.models.OneToOneField

Example:

import auto_prefetch

DJANGO_TENANT_OPTIONS = {
    "MODEL_CLASS": auto_prefetch.Model,
    "MANAGER_CLASS": "auto_prefetch.Manager",
    "QUERYSET_CLASS": "auto_prefetch.QuerySet",
    "FOREIGNKEY_CLASS": auto_prefetch.ForeignKey,
    "ONETOONEFIELD_CLASS": "auto_prefetch.OneToOneField",
}

See Customization for programmatic configuration via model_config.

Form settings

DEFAULT_MULTIPLE_CHOICE_FIELD

Type

class or str

Default

OptionsModelMultipleChoiceField

The form field class used by SelectionsForm for the selections widget. Override to customize how options are displayed.

DJANGO_TENANT_OPTIONS = {
    "DEFAULT_MULTIPLE_CHOICE_FIELD": "yourapp.forms.CustomOptionsField",
}

DISABLE_FIELD_FOR_DELETED_SELECTION

Type

bool

Default

False

Controls how UserFacingFormMixin handles existing records that reference a deleted selection.

  • False (default): The user must select a new option when editing the record.

  • True: The deleted option appears in the form but is disabled, preserving the historical value. The widget is given aria-disabled="true" and a help_text explaining the locked state.

In both cases, deleted options are never shown in forms for new records.

Note

Accessibility: When True, the HTML disabled attribute removes the locked field from the keyboard tab order, so keyboard-only and screen-reader users cannot focus it or reach the adjacent help_text explanation. The disabled attribute is presentational - it prevents the browser from resubmitting the stale value but is not a server-side guarantee, so the surrounding view should treat the field as immutable. If your audience relies on keyboard navigation, present the locked state as a visible alert near the field rather than relying on this setting alone.

Database settings

DB_VENDOR_OVERRIDE

Type

str or None

Default

None

Override automatic database vendor detection for trigger generation. Useful when using a custom database backend (e.g., PostGIS) where the underlying database is a supported vendor.

DJANGO_TENANT_OPTIONS = {
    "DB_VENDOR_OVERRIDE": "postgresql",  # "postgresql", "mysql", "sqlite", or "oracle"
}

Full example

Here’s a complete settings configuration:

from django.db import models

DJANGO_TENANT_OPTIONS = {
    # Required
    "TENANT_MODEL": "myapp.Tenant",

    # Tenant relationships
    "TENANT_ON_DELETE": models.CASCADE,
    "TENANT_MODEL_RELATED_NAME": "%(app_label)s_%(class)s_related",
    "TENANT_MODEL_RELATED_QUERY_NAME": "%(app_label)s_%(class)ss",

    # Option relationships
    "OPTION_ON_DELETE": models.CASCADE,
    "OPTION_MODEL_RELATED_NAME": "%(app_label)s_%(class)s_related",
    "OPTION_MODEL_RELATED_QUERY_NAME": "%(app_label)s_%(class)ss",
    "ASSOCIATED_TENANTS_RELATED_NAME": "%(app_label)s_%(class)s_selections",
    "ASSOCIATED_TENANTS_RELATED_QUERY_NAME": "%(app_label)s_%(class)ss_selected",

    # Database
    "DB_VENDOR_OVERRIDE": None,

    # Forms
    "DISABLE_FIELD_FOR_DELETED_SELECTION": False,
}

System checks

django-tenant-options registers Django system checks that run automatically during manage.py check, migrate, and runserver. These checks validate your model configuration.

Option model checks

Check ID

Level

Description

django_tenant_options.I001

Info

Option model manager doesn’t inherit from OptionManager. Filtering may not work as expected.

django_tenant_options.E002

Error

Option model manager uses a queryset that doesn’t inherit from OptionQuerySet.

django_tenant_options.E003

Error

Option model has no manager inheriting from OptionManager with OptionQuerySet.

django_tenant_options.W007

Warning

Option model may be missing the unique name constraint. Check Meta inheritance.

django_tenant_options.W008

Warning

Option model may be missing the tenant check constraint. Check Meta inheritance.

Selection model checks

Check ID

Level

Description

django_tenant_options.I004

Info

Selection model manager doesn’t inherit from SelectionManager. Filtering may not work as expected.

django_tenant_options.E005

Error

Selection model manager uses a queryset that doesn’t inherit from SelectionQuerySet.

django_tenant_options.E006

Error

Selection model has no manager inheriting from SelectionManager with SelectionQuerySet.

django_tenant_options.W009

Warning

Selection model may be missing the option_not_null check constraint.

django_tenant_options.W010

Warning

Selection model may be missing the tenant_not_null check constraint.

django_tenant_options.W011

Warning

Selection model may be missing the unique_active_selection constraint.

Resolving check failures

Error checks (E002, E003, E005, E006): Ensure your custom managers inherit from OptionManager/SelectionManager and your custom querysets inherit from OptionQuerySet/SelectionQuerySet.

Warning checks (W007-W011): Ensure your model’s Meta class inherits from AbstractOption.Meta or AbstractSelection.Meta:

class MyOption(AbstractOption):
    class Meta(AbstractOption.Meta):  # This is required
        verbose_name = "My Option"

Note

Manager compliance checks (I001, I004, E002, E005) only run when DEBUG = True.

Caching

django-tenant-options can cache the per-tenant option lists returned by OptionQuerySet.options_for_tenant and selected_options_for_tenant. Caching is opt-in and off by default; when disabled, query behavior is identical to the uncached logic.

Enable it in settings.py:

DJANGO_TENANT_OPTIONS = {
    # ...
    "CACHE_OPTIONS": True,          # master switch (default: False)
    "CACHE_TIMEOUT": 300,           # seconds each cached list lives (default: 300)
    "CACHE_KEY_PREFIX": "dto",      # prefix for all cache keys (default: "dto")
    "CACHE_ALIAS": "default",       # which entry in settings.CACHES to use (default: "default")
}

Settings

  • CACHE_OPTIONS (bool, default False) - Master switch. When True, per-tenant option lists are cached. When False, nothing is cached and behavior is unchanged.

  • CACHE_TIMEOUT (int, default 300) - Time-to-live in seconds for each cached list.

  • CACHE_KEY_PREFIX (str, default "dto") - Prefix applied to every cache key this package writes, to avoid collisions with other cache users.

  • CACHE_ALIAS (str, default "default") - Which Django cache backend (from settings.CACHES) to store entries in.

How invalidation works

Each Option model has an integer “namespace version” stored in the cache. Every per-tenant cache key embeds the current version. On post_save and post_delete of any Option or Selection instance, the package bumps that model’s version, which makes all previously cached lists for the model unreachable without enumerating individual keys. Because Options soft-delete via save() (setting the deleted timestamp) and hard-delete via delete(override=True), connecting both post_save and post_delete covers every case. Running python manage.py syncoptions also fires these signals, so default options stay consistent automatically.

Cached entries store only a list of primary keys; reads return a normal QuerySet (Model.objects.filter(pk__in=...)), so the public API and return types are unchanged.

Further reading