Как в Django Rest Framework перенести router.regiter() в декоратор

Написал декоратор который будет регестрировать в переданный router Viewset

def register(router, prefix, basename=None):
    def decorator(viewset):
        if not prefix:
            raise ValueError('Не указано имя Viewset')
        if not issubclass(viewset, viewsets.GenericViewSet):
            raise ValueError('Wrapped class must subclass GenericViewSet.')
        router.register(prefix, viewset, basename)
        return viewset
    return decorator

Но в urls.py я импортирую роутер в месте инициализации, т.е. app.routers

app.routers.py

from rest_framework.routers import DefaultRouter

router = DefaultRouter()

Как я понимаю router будет пустой пока файлы с декораторами не будут импортированны в routers.py. Но мне нужно универсальное решение чтобы распространялось на все файлы проекта.

все верно, пока файлы с декораторами не импортированы, router остаётся пустым.

можно использовать глобальный список для регистраций, например REGISTERED_VIEWSETS, в который будем временно сохранять ViewSets.

# app/routers.py
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
# Глобальный список для отложенной регистрации
REGISTERED_VIEWSETS = []  

def register(router, prefix, basename=None):
    """Декоратор для отложенной регистрации ViewSet"""
    def decorator(viewset):
        if not prefix:
            raise ValueError('Не указано имя ViewSet')
        if not issubclass(viewset, viewsets.GenericViewSet):
            raise ValueError('Wrapped class must subclass GenericViewSet.')
        REGISTERED_VIEWSETS.append((prefix, viewset, basename))
        return viewset
    return decorator

Вместо того, чтобы сразу регистрировать в router, сначала добавим данные в REGISTERED_VIEWSETS.

Теперь в urls.py нужно вызвать регистрацию перед подключением маршрутов

# app/urls.py
from django.urls import path, include
from app.routers import router, REGISTERED_VIEWSETS

for prefix, viewset, basename in REGISTERED_VIEWSETS:
    router.register(prefix, viewset, basename)

urlpatterns = [
    path('api/', include(router.urls)),
]

Теперь можно применять декоратор к ViewSet в любом файле без необходимости явно импортировать router.

from rest_framework import viewsets
from app.routers import register

@register(prefix="users", basename="user")
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

Вернуться на верх