Исправлена ошибка 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:
2025-12-31 01:05:47 +03:00
parent b59ad725cb
commit eb6a3c1874
7 changed files with 184 additions and 39 deletions

View 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