Исправлена ошибка 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

@@ -1,10 +1,16 @@
from django.contrib import admin
from user_roles.models import Role, UserRole
from user_roles.mixins import OwnerOnlyAdminMixin
from tenants.admin_mixins import TenantAdminOnlyMixin
@admin.register(Role)
class RoleAdmin(admin.ModelAdmin):
class RoleAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
"""
Админка ролей.
TenantAdminOnlyMixin - скрывает от public admin (localhost/admin/),
так как таблица Role существует только в схемах тенантов.
"""
list_display = ['code', 'name', 'is_system']
list_filter = ['is_system']
search_fields = ['code', 'name']
@@ -18,10 +24,12 @@ class RoleAdmin(admin.ModelAdmin):
@admin.register(UserRole)
class UserRoleAdmin(OwnerOnlyAdminMixin, admin.ModelAdmin):
class UserRoleAdmin(TenantAdminOnlyMixin, OwnerOnlyAdminMixin, admin.ModelAdmin):
"""
Админка ролей пользователей.
Доступна только владельцу.
TenantAdminOnlyMixin - скрывает от public admin (таблица только в tenant схемах)
OwnerOnlyAdminMixin - доступна только владельцу магазина
ВАЖНО: UserRole изолирован по тенантам автоматически через django-tenants,
поэтому владелец видит только пользователей своего магазина!

View File

@@ -4,12 +4,25 @@
ВАЖНО: Этот backend НЕ использует таблицы Django permissions из public schema!
Он только эмулирует API has_perm(), читая роли из текущей tenant schema.
Это безопасно для мультитенантной архитектуры.
ВАЖНО: Backend проверяет текущую схему перед обращением к tenant-only таблицам.
В public схеме ролевые проверки пропускаются (fallback на стандартные Django permissions).
"""
from django.contrib.auth.backends import ModelBackend
from django.db import connection
from django_tenants.utils import get_public_schema_name
from user_roles.services import RoleService
from user_roles.models import Role
def _is_public_schema():
"""
Проверяет, находимся ли мы в public схеме.
В public схеме нет таблиц tenant-only моделей (UserRole, Role).
"""
return connection.schema_name == get_public_schema_name()
class RoleBasedPermissionBackend(ModelBackend):
"""
Backend, который предоставляет права на основе роли пользователя в текущем тенанте.
@@ -86,6 +99,11 @@ class RoleBasedPermissionBackend(ModelBackend):
if user_obj.is_superuser:
return True
# ВАЖНО: В public схеме нет таблиц UserRole/Role!
# Используем только стандартные Django permissions.
if _is_public_schema():
return False
# Получаем роль пользователя в текущем тенанте
# ВАЖНО: RoleService работает с текущей tenant schema!
user_role = RoleService.get_user_role(user_obj)
@@ -132,6 +150,11 @@ class RoleBasedPermissionBackend(ModelBackend):
if user_obj.is_superuser:
return True
# ВАЖНО: В public схеме нет таблиц UserRole/Role!
# Используем только стандартные Django permissions.
if _is_public_schema():
return False
# Получаем роль пользователя в текущем тенанте
user_role = RoleService.get_user_role(user_obj)
if not user_role: