Breaking changes
- Subfolder tenants get a URLconf built for each tenant (#1067). This fixes subfolder tenants under ASGI (#820, #822), where the URL was resolved against the wrong tenant.
- Removed from
django_tenants.urlresolvers:TenantPrefixPattern,tenant_patterns()andget_dynamic_tenant_prefixed_urlconf(). get_subfolder_urlconf()now returns a module rather than a dotted path. Aget_urlconf()override that returns a string still works.- Custom
handler400,handler403,handler404andhandler500on the root URLconf are used for subfolder tenants. A 404 in a subfolder tenant whose root URLconf has nohandler404no longer errors.
- Removed from
schema_exists()compares names exactly by default (#1251). PostgreSQL schema names are case sensitive, so"C2"and"c2"are two schemas. If your code relied on the old case-insensitive match, for instance to check whether a name would collide with an existing schema, passcase_sensitive=False.- Adding a tenant whose schema name differs only in case from an existing tenant's is refused with a
ValidationError(#1251). Existing tenants that already collide are left alone. - Migration output is prefixed with the schema even when it isn't going to a terminal (#1216, via #1273). CI logs, Docker logs and files now get the prefix, and the
schema_migrate_messagesignal is now sent for that output. "Applying x..." appears while a migration runs, and its " OK" stays on the same line.
Fixes
clone_schemahandles a partial unique index in a schema whose name needs quoting, such as one containing a hyphen. Before, it failed withsyntax error at or near "TABLESPACE"(#1270).- With
TENANT_LIMIT_SET_CALLS, the cachedsearch_pathis cleared on a savepoint rollback. PostgreSQL reverts the path on the rollback, so the connection could otherwise read another tenant's rows (#1263). - The
search_pathis set the same way on psycopg2 and psycopg3, and is cleared on rollback and close (#1249). create_tenantstops with the reason when the tenant or domain can't be saved, instead of clearing everything and asking again for ever (#1194).delete_tenantdeletes the tenant when you confirm the prompt (#1252).all_tenants_commandworks; before, every call raisedNotImplementedError(#1253).- A
FakeTenantwithout adomain_subfolderno longer raises anAttributeError(#1272, from #1031). TenantRequestFactorysetsrequest.tenant.domain_urlfrom the request's host (#1132).
Features
TENANT_MULTIPROCESSING_MAX_TASKS_PER_CHILDrecycles the multiprocessing executor's workers. A worker is replaced after this many tasks, which is this setting ×TENANT_MULTIPROCESSING_CHUNKStenants (#1227).- Multi-type tenants can clone from a template of their own type, named in
TENANT_TYPES[type]['BASE_SCHEMA'](#1265, #533).
Documentation
- Notes on using django-tenants securely (#1266).
Dependencies
- psycopg can now be any version below 3.4 (#1208).
- Development dependency updates: docutils, gunicorn and others.
Thanks to everyone who contributed: @RJPercival, @Amirshox, @bishnusyangja, @dexbleeker, @hexponent, @pranaysai27, @McDonnellJoseph and @BasVerlooy.