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 |
|
Default |
|
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 |
Default |
|
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 |
Default |
|
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 |
Default |
|
MANAGER_CLASS¶
Type |
class or |
Default |
|
QUERYSET_CLASS¶
Type |
class or |
Default |
|
FOREIGNKEY_CLASS¶
Type |
class or |
Default |
|
ONETOONEFIELD_CLASS¶
Type |
class or |
Default |
|
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 |
Default |
|
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 |
|
Default |
|
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 givenaria-disabled="true"and ahelp_textexplaining 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 |
|
Default |
|
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 |
|---|---|---|
|
Info |
Option model manager doesn’t inherit from |
|
Error |
Option model manager uses a queryset that doesn’t inherit from |
|
Error |
Option model has no manager inheriting from |
|
Warning |
Option model may be missing the unique name constraint. Check Meta inheritance. |
|
Warning |
Option model may be missing the tenant check constraint. Check Meta inheritance. |
Selection model checks¶
Check ID |
Level |
Description |
|---|---|---|
|
Info |
Selection model manager doesn’t inherit from |
|
Error |
Selection model manager uses a queryset that doesn’t inherit from |
|
Error |
Selection model has no manager inheriting from |
|
Warning |
Selection model may be missing the |
|
Warning |
Selection model may be missing the |
|
Warning |
Selection model may be missing the |
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, defaultFalse) - Master switch. WhenTrue, per-tenant option lists are cached. WhenFalse, nothing is cached and behavior is unchanged.CACHE_TIMEOUT(int, default300) - 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 (fromsettings.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¶
Models Guide – Using these settings in your models
Forms Guide – Form-related settings in action
Customization – Advanced configuration patterns
API Reference – Auto-generated documentation from source