Исправлена ошибка public admin для мультитенантной архитектуры
Проблема: при входе в localhost/admin/ (public схема) возникала ошибка "relation user_roles_userrole does not exist", так как tenant-only таблицы не существуют в public схеме. Решение: - Создан TenantAdminOnlyMixin для скрытия tenant-only моделей от public admin - Применён миксин ко всем ModelAdmin классам в tenant-only приложениях: user_roles, customers, orders, inventory, products - Добавлена проверка _is_public_schema() в RoleBasedPermissionBackend для предотвращения запросов к tenant-only таблицам в public схеме Теперь: - localhost/admin/ показывает только public модели (Client, Domain, User) - shop.localhost/admin/ показывает все модели магазина 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
91
myproject/tenants/admin_mixins.py
Normal file
91
myproject/tenants/admin_mixins.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Миксины для Django Admin в мультитенантной архитектуре.
|
||||
|
||||
ЗАЧЕМ ЭТО НУЖНО:
|
||||
================
|
||||
В django-tenants есть две схемы БД:
|
||||
- public: общая схема (тенанты, домены, пользователи)
|
||||
- tenant: отдельная схема для каждого магазина (товары, заказы, клиенты)
|
||||
|
||||
Проблема: Django Admin регистрирует ВСЕ модели глобально.
|
||||
Когда суперадмин заходит на localhost/admin/ (public схема),
|
||||
Django пытается показать sidebar со ВСЕМИ моделями, включая
|
||||
tenant-only модели (Order, Product, UserRole).
|
||||
|
||||
Но таблицы этих моделей существуют только в схемах тенантов!
|
||||
В public схеме их нет -> ошибка "relation does not exist".
|
||||
|
||||
РЕШЕНИЕ:
|
||||
========
|
||||
Миксин TenantAdminOnlyMixin скрывает модель от админки,
|
||||
если мы находимся в public схеме. Модель просто не показывается
|
||||
в sidebar и недоступна по URL.
|
||||
|
||||
ИСПОЛЬЗОВАНИЕ:
|
||||
==============
|
||||
from tenants.admin_mixins import TenantAdminOnlyMixin
|
||||
|
||||
@admin.register(Order)
|
||||
class OrderAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
...
|
||||
|
||||
Теперь Order будет виден только в админке тенанта (shop.localhost/admin/),
|
||||
но не в public админке (localhost/admin/).
|
||||
"""
|
||||
from django_tenants.utils import get_public_schema_name
|
||||
|
||||
|
||||
class TenantAdminOnlyMixin:
|
||||
"""
|
||||
Миксин для скрытия tenant-only моделей от public admin.
|
||||
|
||||
Как работает:
|
||||
- has_module_permission() вызывается Django для проверки,
|
||||
показывать ли модель в sidebar админки
|
||||
- Мы проверяем текущую схему БД
|
||||
- Если это public схема -> возвращаем False (скрыть)
|
||||
- Если это схема тенанта -> возвращаем True (показать)
|
||||
"""
|
||||
|
||||
def has_module_permission(self, request):
|
||||
"""
|
||||
Скрыть модуль (группу моделей) от public schema админки.
|
||||
|
||||
Вызывается при отрисовке sidebar и при доступе к URL модели.
|
||||
"""
|
||||
from django.db import connection
|
||||
|
||||
# Получаем имя public схемы (обычно 'public')
|
||||
public_schema = get_public_schema_name()
|
||||
|
||||
# Если мы в public схеме - скрываем модель
|
||||
if connection.schema_name == public_schema:
|
||||
return False
|
||||
|
||||
# В схеме тенанта - показываем (используем стандартную проверку)
|
||||
return super().has_module_permission(request)
|
||||
|
||||
|
||||
class PublicAdminOnlyMixin:
|
||||
"""
|
||||
Обратный миксин - показывать модель ТОЛЬКО в public admin.
|
||||
|
||||
Полезно для моделей типа Client, Domain, TenantRegistration,
|
||||
которые должны быть доступны только суперадмину на главном домене.
|
||||
|
||||
Примечание: обычно не нужен, так как эти модели и так
|
||||
существуют только в public схеме.
|
||||
"""
|
||||
|
||||
def has_module_permission(self, request):
|
||||
"""Показать модуль только в public schema админке."""
|
||||
from django.db import connection
|
||||
|
||||
public_schema = get_public_schema_name()
|
||||
|
||||
# Показываем только в public схеме
|
||||
if connection.schema_name == public_schema:
|
||||
return super().has_module_permission(request)
|
||||
|
||||
return False
|
||||
Reference in New Issue
Block a user