Admin
Admin helpers for multi-tenant projects.
This module contains logic to restrict access to certain Django admin models so they are only visible and editable from the master tenant. The typical use-case might be the project where a subset of models (for example global configuration, billing plans, or shared resources) should only be managed at a single, centrally-administered tenant and hidden from per-tenant admin interfaces.
How it works
- The
TenantRestrictAdminMixinis mixed into existing ModelAdmin classes at import time for selected models. - For those models the mixin overrides permission checks and model visibility so that only the configured master tenant may see and operate on them.
- Models are selected for restriction if any of the following are true:
- the app config defines
master_managed = True - the model class defines
master_managed = True - the model class defines
tenant_managed = False(i.e. not tenant-scoped)
Configuration
- The master tenant name is read from
settings.MASTER_TENANT_NAME. - The list of apps to inspect comes from :func:
get_custom_appswhich allows consumers to control which installed apps are evaluated.
Notes for maintainers
- This module runs at import time and mutates
admin.siteby unregistering and re-registering ModelAdmin classes. Import order matters: it is important this module is imported after apps have been loaded and their ModelAdmin registrations have occurred. Thusdjango_omnitenantmust be placed after all the custom defined apps in the project in the INSTALLED_APPS.
TenantRestrictAdminMixin
Bases: ModelAdmin
A small mixin that restricts admin access to the master tenant.
This mixin is intentionally minimal: it overrides the standard ModelAdmin permission checks to return permissive results only when the current request is served under the master tenant. When the request's tenant is not the master tenant, the mixin denies visibility and all CRUD permissions so the model is hidden from the non-master tenant's admin UI.
Implementation details
_is_master_tenant: helper that inspectsrequest.tenantand compares itsnametosettings.MASTER_TENANT_NAME. It is small and isolated so it can be overridden in tests if necessary.- Each of the permission hooks used by Django admin
(
get_model_perms,has_*_permission) delegates to_is_master_tenantto make the logic explicit and consistent.
Override considerations
If a project needs finer-grained control (for example allowing
view-only access to non-master tenants) you can extend this mixin
and override the individual has_*_permission methods.
Source code in django_omnitenant/admin.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
get_model_perms(request)
Return the model permissions dictionary for the current request.
When not in the master tenant an empty dict is returned which causes Django admin to hide the model from the index/listing.
Source code in django_omnitenant/admin.py
85 86 87 88 89 90 91 92 93 94 | |
has_module_permission(request)
Whether the model module should be visible in the admin index.
Source code in django_omnitenant/admin.py
96 97 98 99 | |
has_view_permission(request, obj=None)
Whether request can view instances of this model.
Source code in django_omnitenant/admin.py
101 102 103 104 | |
has_add_permission(request)
Whether request can add new instances of this model.
Source code in django_omnitenant/admin.py
106 107 108 109 | |
has_change_permission(request, obj=None)
Whether request can modify the given object (or any object).
Source code in django_omnitenant/admin.py
111 112 113 114 | |
has_delete_permission(request, obj=None)
Whether request can delete the given object (or any object).
Source code in django_omnitenant/admin.py
116 117 118 119 | |