Оптимизация N+1 запросов к ролям пользователей через select_related в middleware

This commit is contained in:
2026-01-11 14:19:28 +03:00
parent c070e42cab
commit ed4d509a4e
2 changed files with 33 additions and 1 deletions

View File

@@ -33,6 +33,24 @@ class TenantAdminAccessMiddleware:
}, status=403) }, status=403)
def __call__(self, request): def __call__(self, request):
# Оптимизация: загружаем роль пользователя один раз для всего запроса
if hasattr(request, 'user') and request.user.is_authenticated:
schema_name = getattr(connection, 'schema_name', 'public')
# Только для tenant схем и CustomUser загружаем роль с select_related
if schema_name != 'public':
from accounts.models import CustomUser
if isinstance(request.user, CustomUser):
# Проверяем, не загружена ли уже роль
if not hasattr(request.user, '_role_prefetched'):
try:
# Загружаем пользователя с ролью через select_related
request.user = CustomUser.objects.select_related(
'tenant_role__role'
).get(pk=request.user.pk)
request.user._role_prefetched = True
except CustomUser.DoesNotExist:
pass
# Проверяем, это admin URL? # Проверяем, это admin URL?
if request.path.startswith('/admin/'): if request.path.startswith('/admin/'):
# Импортируем здесь чтобы избежать circular imports # Импортируем здесь чтобы избежать circular imports

View File

@@ -110,8 +110,22 @@ class RoleService:
@staticmethod @staticmethod
def get_user_role(user): def get_user_role(user):
"""Получить роль пользователя в текущем тенанте""" """
Получить роль пользователя в текущем тенанте.
Оптимизация: использует уже загруженные данные если есть select_related.
"""
try: try:
# Проверяем, есть ли уже загруженная роль через select_related
if hasattr(user, 'tenant_role'):
# Проверяем, что tenant_role загружен (а не RelatedObjectDoesNotExist)
try:
user_role = user.tenant_role
if user_role.is_active and hasattr(user_role, 'role'):
return user_role.role
except UserRole.DoesNotExist:
pass
# Если нет prefetch - делаем запрос
user_role = UserRole.objects.get(user=user, is_active=True) user_role = UserRole.objects.get(user=user, is_active=True)
return user_role.role return user_role.role
except UserRole.DoesNotExist: except UserRole.DoesNotExist: