fix: Исправлена ошибка ForeignKey в products - замена PlatformAdmin на CustomUser
Устранена ошибка ValueError "Cannot query 'email': Must be 'PlatformAdmin' instance"
при доступе CustomUser к странице /products/.
Проблема:
- Модели products (TENANT_APPS) использовали get_user_model() для ForeignKey
- get_user_model() возвращал PlatformAdmin (AUTH_USER_MODEL)
- Но tenant модели должны ссылаться на CustomUser (tenant пользователей)
- Это создавало конфликт типов при запросах от CustomUser
Изменения:
1. products/models/base.py:
- Убран get_user_model()
- BaseProductEntity.archived_by теперь ForeignKey('accounts.CustomUser')
2. products/models/categories.py:
- Убран get_user_model()
- ProductCategory.deleted_by теперь ForeignKey('accounts.CustomUser')
3. products/models/import_job.py:
- Убран get_user_model()
- ProductImportJob.user теперь ForeignKey('accounts.CustomUser')
4. Создана миграция 0002 с data migration:
- Очистка некорректных ссылок (установка NULL)
- Изменение типа ForeignKey полей с PlatformAdmin на CustomUser
5. user_roles/auth_backend.py:
- Добавлена функция _is_tenant_user() для проверки типа пользователя
- Исправлена логика has_perm() и has_module_perms()
- CustomUser теперь не проверяется через ModelBackend.has_perm()
6. admin_access_middleware.py:
- Улучшены сообщения об ошибках доступа
- Добавлен рендеринг через шаблон access_denied.html
7. templates/errors/access_denied.html:
- Новый шаблон для красивого отображения ошибок доступа
Результат:
- CustomUser может без ошибок работать со страницей /products/
- Корректная архитектура: tenant модели ссылаются на tenant пользователей
- PlatformAdmin продолжает работать корректно
- Чистое решение без костылей
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Middleware для ограничения доступа к админке Django.
|
||||
Middleware для ограничения доступа к админке.
|
||||
|
||||
SECURITY: Этот middleware обеспечивает изоляцию аутентификации между
|
||||
PlatformAdmin (public schema) и CustomUser (tenant schemas).
|
||||
@@ -10,13 +10,13 @@ PlatformAdmin (public schema) и CustomUser (tenant schemas).
|
||||
- На TENANT доменах: только PlatformAdmin с is_superuser=True (для поддержки)
|
||||
или CustomUser с is_superuser=True (системный пользователь тенанта)
|
||||
"""
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.shortcuts import render
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class TenantAdminAccessMiddleware:
|
||||
"""
|
||||
Middleware для контроля доступа к Django Admin.
|
||||
Middleware для контроля доступа к административным разделам.
|
||||
|
||||
Обеспечивает разделение между:
|
||||
- PlatformAdmin (администраторы платформы) на public домене
|
||||
@@ -26,6 +26,12 @@ class TenantAdminAccessMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def _render_error(self, request, message):
|
||||
"""Рендерит страницу ошибки доступа."""
|
||||
return render(request, 'errors/access_denied.html', {
|
||||
'message': message
|
||||
}, status=403)
|
||||
|
||||
def __call__(self, request):
|
||||
# Проверяем, это admin URL?
|
||||
if request.path.startswith('/admin/'):
|
||||
@@ -44,27 +50,30 @@ class TenantAdminAccessMiddleware:
|
||||
if is_public:
|
||||
# PUBLIC DOMAIN: только PlatformAdmin
|
||||
if not is_platform_admin:
|
||||
return HttpResponseForbidden(
|
||||
"Доступ запрещен. Админка платформы доступна только "
|
||||
"для администраторов платформы. "
|
||||
"Если вы владелец магазина, перейдите на домен вашего магазина."
|
||||
return self._render_error(
|
||||
request,
|
||||
'Административная панель платформы доступна только '
|
||||
'для администраторов платформы. '
|
||||
'Если вы владелец магазина, перейдите на домен вашего магазина.'
|
||||
)
|
||||
else:
|
||||
# TENANT DOMAIN: PlatformAdmin (superuser) или CustomUser (superuser)
|
||||
if is_platform_admin:
|
||||
# PlatformAdmin на tenant домене - только суперадмин
|
||||
if not user.is_superuser:
|
||||
return HttpResponseForbidden(
|
||||
"Доступ запрещен. Только суперадминистраторы платформы "
|
||||
"могут входить в админку тенантов."
|
||||
return self._render_error(
|
||||
request,
|
||||
'Только суперадминистраторы платформы '
|
||||
'могут получить доступ к этому разделу.'
|
||||
)
|
||||
else:
|
||||
# CustomUser на tenant домене
|
||||
if not user.is_superuser:
|
||||
return HttpResponseForbidden(
|
||||
"Доступ запрещен. Только системные администраторы тенанта "
|
||||
"могут входить в Django Admin. "
|
||||
"Используйте панель управления магазином."
|
||||
return self._render_error(
|
||||
request,
|
||||
'Только системные администраторы тенанта '
|
||||
'могут получить доступ к этому разделу. '
|
||||
'Используйте панель управления магазином.'
|
||||
)
|
||||
|
||||
response = self.get_response(request)
|
||||
|
||||
Reference in New Issue
Block a user