Django REST Framework/DRF 일반

[DRF] 공식 문서 - Routers 정리

bluebamus 2024. 1. 17. 18:06

 1. Routers

   1) 정의

      - 일부 웹 프레임워크, 예를 들면 Rails 같은 경우는, 애플리케이션의 URL을 들어오는 요청을 처리하는 로직과 어떻게 연결할지 자동으로 판단하는 기능을 제공한다.

      - REST 프레임워크는 Django에 자동 URL 라우팅 지원을 추가하고, 이를 통해 개발자의 뷰 로직을 일련의 URL들에 간편하고 빠르며 일관된 방식으로 연결하는 간단한 방법을 제공해준다.

 

   2) Usage

      - 다음은 SimpleRouter를 사용하는 간단한 URL 설정의 예시이다.

from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls

 

      - register() 메서드에는 두개의 필수 인자가 있다.

         - prefix - 이 라우트 세트에 사용할 URL 접두사이다.

         - viewset - 뷰셋 클래스이다.

 

      - 선택적으로, 추가적인 인자를 지정할 수도 있다.

         - basename - 생성될 URL 이름의 기본값을 지정한다. 만약 설정되지 않으면, 뷰셋의 queryset 속성에 따라 basename이 자동으로 생성된다. 단, 뷰셋에 queryset 속성이 없다면, 뷰셋을 등록할 때 반드시 basename을 설정해야 한다.

 

      - 위의 예시는 다음과 같은 URL 패턴을 생성한다.

         - URL 패턴: ^users/$ Name: 'user-list'
         - URL 패턴 : ^users/{pk}/$ Name: 'user-detail'
         - URL 패턴: ^accounts/$ Name: 'account-list'
         - URL 패턴: ^accounts/{pk}/$ Name: 'account-detail'


      - 참고: basename 인자는 뷰 이름 패턴의 초기 부분을 지정하는 데 사용됩니다. 위의 예시에서는 'user' 또는 'account' 부분이 해당된다.

   

      - 일반적으로 basename 인자를 지정할 필요는 없지만, 사용자 정의 get_queryset 메서드를 정의한 뷰셋이 있는 경우, 뷰셋에 .queryset 속성이 설정되어 있지 않을 수 있다. 그런 뷰셋을 등록하려고 하면 다음과 같은 오류를 볼 수 있다.

'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.

 

      - 이는 모델 이름에서 자동으로 결정할 수 없기 때문에, 뷰셋을 등록할 때 basename 인자를 반드시 직접 설정해야 함을 의미한다.


         1. 라우터와 함께 include 사용하기

            - 라우터 인스턴스에 있는 .urls 속성은 표준적인 URL 패턴의 리스트이다. 이 URL들을 포함시키는 방식은 여러 가지가 있다.

            - 예를 들어, 기존 뷰의 목록에 router.urls를 추가할 수 있다.

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)

urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
]

urlpatterns += router.urls

 

            - 예를 들어, 기존 뷰에 router.urls를 추가할 수 있또는 다음과 같이 Django의 include 함수를 사용할 수도 있다.

urlpatterns = [
    path('forgot-password', ForgotPasswordFormView.as_view()),
    path('', include(router.urls)),
]

 

            - 애플리케이션 네임스페이스와 함께 include를 사용할 수도 있다.

urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/', include((router.urls, 'app_name'))),
]

 

            - 또는 애플리케이션 네임스페이스와 인스턴스 네임스페이스 둘 다 사용할 수 있다.

urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
]

 

            - 자세한 내용은 Django의 URL 네임스페이스 문서와 include API 참조를 참고.

               - https://docs.djangoproject.com/en/5.0/ref/urls/#include

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 


      - 참고: 하이퍼링크된 시리얼라이저와 네임스페이싱을 함께 사용하는 경우, 시리얼라이저의 view_name 매개변수가 네임스페이스를 올바르게 반영하도록 해야 한다. 위의 예시에서는 사용자 상세 뷰로 하이퍼링크된 시리얼라이저 필드에 대해 'view_name='app_name:user-detail''와 같은 매개변수를 포함해야 한다.

 

      - 자동 view_name 생성은 %(model_name)-detail과 같은 패턴을 사용한다. 모델 이름이 실제로 충돌하지 않는 한, 하이퍼링크된 시리얼라이저를 사용할 때 Django REST Framework 뷰에 네임스페이스를 사용하지 않는 것이 더 나을 수 있다.



       - 'app_name'은 애플리케이션 네임스페이스로서, 동일한 Django 프로젝트 내에서 여러 앱의 URL 패턴을 구분하기 위해 사용된다.

         - 'instance_name'은 인스턴스 네임스페이스로서, 동일한 애플리케이션 내에서 여러 인스턴스의 URL 패턴을 구분하기 위해 사용된다.

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)

# 애플리케이션 네임스페이스만 사용하는 경우
urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/', include((router.urls, 'users_app'))),
]

# 이 경우 'users_app:user-list'나 'users_app:user-detail'와 같이 역참조할 수 있습니다.
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)

# 애플리케이션 네임스페이스와 인스턴스 네임스페이스를 함께 사용하는 경우
urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/', include((router.urls, 'users_app'), namespace='v1')),
]

# 이 경우 'v1:user-list'나 'v1:user-detail'와 같이 역참조할 수 있습니다.
router_v1 = routers.SimpleRouter()
router_v1.register(r'users', UserViewSet_v1)
router_v1.register(r'accounts', AccountViewSet_v1)

router_v2 = routers.SimpleRouter()
router_v2.register(r'users', UserViewSet_v2)
router_v2.register(r'accounts', AccountViewSet_v2)

# 같은 애플리케이션이지만 다른 버전의 뷰셋을 사용하는 경우
urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/v1/', include((router_v1.urls, 'users_app'), namespace='v1')),
    path('api/v2/', include((router_v2.urls, 'users_app'), namespace='v2')),
]

# 이 경우 'v1:user-list', 'v1:user-detail' 또는 'v2:user-list', 'v2:user-detail'와 같이 역참조할 수 있습니다.

 

         - namespace가 명시되어 있는 경우, 'users_app'는 사용되지 않는다. 이는 Django REST Framework의 특징 중 하나이다.

         - Django의 include 함수는 URLconf 모듈을 가져와 URL 패턴 목록에 포함시키는 역할을 한다. include 함수의 첫 번째 인자는 URLconf 모듈을 가리킨다. 이때, URLconf 모듈은 단순한 Python 모듈이며 urlpatterns 변수를 포함해야 한다.
         - 따라서, include 함수의 첫 번째 인자로 (router.urls, 'users_app')를 넘기게 되면, 'users_app'는 애플리케이션 네임스페이스를 나타낸다. 이 네임스페이스는 해당 애플리케이션의 모든 뷰를 역참조할 때 사용된다.

 

         - 하지만, namespace 인자가 명시되어 있는 경우, 이 namespace가 애플리케이션 네임스페이스를 오버라이드하게 된다. 즉, 이 경우 'v2'가 실제로 사용되는 네임스페이스가 되고, 'users_app'는 무시되게 된다.
         - 따라서, 두 정의가 같이 사용되는 경우는 없다. 이는 Django와 Django REST Framework의 설계 의도에 따른 것이다.


 

         2. 추가 액션을 위한 라우팅

            - 뷰셋은 @action 데코레이터를 사용하여 메서드에 추가 액션을 표시하여 라우팅할 수 있다. 이 추가 액션은 생성된 라우트에 포함된다.

 

            - 예를 들어, UserViewSet 클래스에 있는 set_password 메서드를 보자.

# urls.py
router.register(r'users', UserViewSet)

# views.py
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action

class UserViewSet(ModelViewSet):
    ...

    @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
    def set_password(self, request, pk=None):
        ...

 

            - 다음과 같은 라우트가 생성된다.

               - URL 패턴: ^users/{pk}/set_password/$

               - URL 이름: 'user-set-password'

 

            - 기본적으로 URL 패턴은 메서드 이름을 기반으로 하고, URL 이름은 ViewSet.basename와 하이픈으로 연결된 메서드 이름의 조합이다. 이러한 값들에 대해 기본 설정을 사용하고 싶지 않다면, 대신 @action 데코레이터에 url_path와 url_name 인자를 제공할 수 있다.

 

            - 예를 들어, 사용자 정의 액션에 대한 URL을 ^users/{pk}/change-password/$로 변경하려면 다음과 같이 작성할 수 있다.

from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action

class UserViewSet(ModelViewSet):
    ...

    @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
            url_path='change-password', url_name='change_password')
    def set_password(self, request, pk=None):
        ...

 

               - 위의 예시는 이제 다음과 같은 URL 패턴을 생성한다.

                  - URL 경로: ^users/{pk}/change-password/$
                  - URL 이름: 'user-change_password'

 

 2. API Guide

   1) SimpleRouter

      - 이 라우터는 표준적인 목록(list), 생성(create), 검색(retrieve), 업데이트(update), 부분 업데이트(partial_update), 삭제(destroy) 액션에 대한 루트를 포함한다. 뷰셋은 @action 데코레이터를 사용하여 추가적인 메서드를 라우팅할 수도 있다.

 

URL Style HTTP Method Action URL Name
{prefix}/ GET list {basename}-list
POST create
{prefix}/{url_path}/ GET, or as specified by `methods` argument create`@action(detail=False)` decorated method {basename}-{url_name}
{prefix}/{lookup}/ GET retrieve {basename}-detai
PUT update
PATCH partial_update
DELETE destroy
{prefix}/{lookup}/{url_path}/ GET, or as specified by `methods` argument `@action(detail=True)` decorated method {basename}-{url_name}

 

      - 기본적으로 SimpleRouter에 의해 생성된 URL들은 마지막에 슬래시(/)가 붙는다. 이 동작은 라우터를 인스턴스화할 때 trailing_slash 인자를 False로 설정함으로써 수정할 수 있다.

router = SimpleRouter(trailing_slash=False)

 

      - 슬래시(/)를 끝에 붙이는 것은 Django에서 일반적이지만, Rails와 같은 다른 일부 프레임워크에서는 기본적으로 사용하지 않는다. 어떤 스타일을 선택할지는 대부분 개인의 선호에 따라 결정되며, 일부 자바스크립트 프레임워크는 특정한 라우팅 스타일을 요구할 수 있다.

router = SimpleRouter(use_regex_path=False)

      - 참고: use_regex_path=False는 Django 2.x 이상에서만 작동한다. 이 기능은 2.0.0에서 도입되었다. 릴리스 노트 참조.

         - https://docs.djangoproject.com/en/2.0/releases/2.0/#simplified-url-routing-syntax

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com


      - 라우터는 슬래시와 점 문자를 제외한 모든 문자를 포함하는 조회 값과 일치한다. 더 제한적인 (또는 관대한) 조회 패턴을 위해, 뷰셋의 lookup_value_regex 속성을 설정하거나 경로 변환기를 사용하는 경우 lookup_value_converter를 설정하면 된다. 예를 들어, 조회를 유효한 UUID로 제한할 수 있다.

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    lookup_field = 'my_model_id'
    lookup_value_regex = '[0-9a-f]{32}'

class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    lookup_field = 'my_model_uuid'
    lookup_value_converter = 'uuid'

 

   2) DefaultRouter

      - 이 라우터는 위의 SimpleRouter와 유사하지만, 모든 목록 뷰로의 하이퍼링크를 포함하는 응답을 반환하는 기본 API 루트 뷰를 추가로 포함한다. 또한 선택적인 .json 스타일의 형식 접미사에 대한 루트도 생성한다.

 

URL Style HTTP Method Action URL Name
[.format] GET automatically generated root view api-root
{prefix}/[.format] GET list {basename}-list
POST create
{prefix}/{url_path}/[.format] GET, or as specified by `methods` argument `@action(detail=False)` decorated method {basename}-{url_name}
{prefix}/{lookup}/[.format] GET retrieve {basename}-detai
PUT update
PATCH partial_update
DELETE destroy
{prefix}/{lookup}/{url_path}/[.format] GET, or as specified by `methods` argument `@action(detail=True)` decorated method {basename}-{url_name}

 

      - SimpleRouter와 마찬가지로, 라우터를 인스턴스화할 때 trailing_slash 인자를 False로 설정함으로써 URL 루트의 끝에 붙는 슬래시를 제거할 수 있다.

router = DefaultRouter(trailing_slash=False)

 

 3. Custom Routers

   1) 정의

      - 사용자 정의 라우터를 구현하는 것은 자주 필요한 일은 아니지만, API의 URL이 어떻게 구조화되어야 하는지에 대한 특정 요구사항이 있을 경우 유용할 수 있다. 이렇게 하면 URL 구조를 재사용 가능한 방식으로 캡슐화하여 각 새로운 뷰에 대해 URL 패턴을 명시적으로 작성할 필요가 없게 된다.

 

      - 사용자 정의 라우터를 구현하는 가장 간단한 방법은 기존 라우터 클래스 중 하나를 서브클래싱하는 것이다. .routes 속성은 각 뷰셋에 매핑될 URL 패턴을 템플릿화하는 데 사용된다. .routes 속성은 Route라는 명명된 튜플의 목록이다.

 

      - Route라는 명명된 튜플에 대한 인자는 다음과 같다.

         - url: 라우팅할 URL을 나타내는 문자열입니다. 다음 형식 문자열을 포함할 수 있다.
            - {prefix} - 이 라우트 세트에 사용할 URL 접두사이다.
            - {lookup} - 단일 인스턴스와 일치시키기 위해 사용하는 조회 필드이다.
            - {trailing_slash} - trailing_slash 인수에 따라 '/' 또는 빈 문자열이다.
         - mapping: HTTP 메서드 이름을 뷰 메서드에 매핑한다.
         - name: 역참조 호출에서 사용하는 URL의 이름이다. 다음 형식 문자열을 포함할 수 있다.
            - {basename} - 생성된 URL 이름에 사용할 기본값이다.

         - initkwargs: 뷰를 인스턴스화할 때 전달해야 하는 추가 인수의 딕셔너리이다. detail, basename, suffix 인수는 뷰셋 탐색에 예약되어 있으며, 브라우저 가능 API에서도 뷰 이름과 breadcrumb links를 생성하는 데 사용된다.

            - breadcrumb links : 사이트나 웹 앱에서 유저의 위치를 보여주는 부차적인 내비게이션 시스템을 뜻한다

 

   2) Customizing dynamic routes

      - @action 데코레이터의 라우팅 방식도 커스터마이징할 수 있다. .routes 목록에 DynamicRoute라는 명명된 튜플을 포함시키고, 목록 기반 라우트와 세부 기반 라우트에 적합하게 detail 인자를 설정면 된다. detail 외에도 DynamicRoute에 대한 인자는 다음과 같다.
         - url: 라우팅될 URL을 나타내는 문자열이다. Route와 동일한 형식 문자열을 포함할 수 있으며, 추가로 {url_path} 형식 문자열을 허용한다.
         - name: 역참조 호출에 사용되는 URL의 이름이다. 다음 형식 문자열을 포함할 수 있다.
            - {basename} - 생성된 URL 이름에 사용할 기본값이다.
            - {url_name} - @action에 제공된 url_name이다.

         - initkwargs: 뷰를 인스턴스화할 때 전달해야 하는 추가 인자를 담은 딕셔너리이다.

 

   3) Example

      - 다음 예제는 목록과 검색 액션만 라우팅하며, 끝에 슬래시를 붙이는 관례를 사용하지 않는다.

from rest_framework.routers import Route, DynamicRoute, SimpleRouter

class CustomReadOnlyRouter(SimpleRouter):
    """
    A router for read-only APIs, which doesn't use trailing slashes.
    """
    routes = [
        Route(
            url=r'^{prefix}$',
            mapping={'get': 'list'},
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        Route(
            url=r'^{prefix}/{lookup}$',
            mapping={'get': 'retrieve'},
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Detail'}
        ),
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        )
    ]

 

      - 간단한 뷰셋에 대해 CustomReadOnlyRouter가 생성할 루트를 살펴보자.

# views.py
class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    A viewset that provides the standard actions
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_field = 'username'

    @action(detail=True)
    def group_names(self, request, pk=None):
        """
        Returns a list of all the group names that the given
        user belongs to.
        """
        user = self.get_object()
        groups = user.groups.all()
        return Response([group.name for group in groups])
# urls.py

router = CustomReadOnlyRouter()
router.register('users', UserViewSet)
urlpatterns = router.urls

 

      - 다음과 같은 매핑이 생성될 것이다.

URL HTTP Method Action URL Name
/users GET list user-list
/users/{username} GET retrieve user-detail
/users/{username}/group_names GET group_names user-group-names

 

      - .routes 속성을 설정하는 또 다른 예시를 보려면 SimpleRouter 클래스의 소스 코드를 참조할 수 있다.

 

   4) Advanced custom routers

      - 완전히 커스텀된 동작을 제공하려면 BaseRouter를 오버라이드하고 get_urls(self) 메서드를 오버라이드할 수 있다. 이 메서드는 등록된 뷰셋을 검사하고 URL 패턴의 목록을 반환해야 한다. 등록된 prefix, viewset, basename 튜플은 self.registry 속성에 접근하여 검사할 수 있다.

      - 또한 get_default_basename(self, viewset) 메서드를 오버라이드하거나, 라우터에 뷰셋을 등록할 때 항상 basename 인자를 명시적으로 설정하려고 할 수도 있다.

 

      - example

# views.py
from rest_framework import viewsets
from .models import User
from .serializers import UserSerializer

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
# routers.py
from rest_framework.routers import BaseRouter
from django.urls import path

class CustomRouter(BaseRouter):
    def get_urls(self):
        """
        get_urls 메서드는 등록된 뷰셋을 검사하고 URL 패턴의 목록을 반환합니다.
        """
        urls = []
        for prefix, viewset, basename in self.registry:
            urls.append(path(f'{prefix}/', viewset.as_view({'get': 'list'}), name=f'{basename}-list'))
            urls.append(path(f'{prefix}/<int:pk>/', viewset.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}), name=f'{basename}-detail'))
            urls.append(path(f'{prefix}/', viewset.as_view({'post': 'create'}), name=f'{basename}-create'))
        return urls

    def get_default_basename(self, viewset):
        """
        get_default_basename 메서드는 뷰셋에 대한 기본 basename을 반환합니다.
        """
        return viewset.queryset.model.__name__.lower()

# 라우터를 인스턴스화하고 뷰셋을 등록합니다.
router = CustomRouter()
router.register(r'users', UserViewSet)

 

      - 위의 코드에서 CustomRouter는 BaseRouter를 상속받아 두 개의 메서드를 오버라이드한다.

 

      - get_urls: 이 메서드는 라우터가 URL 패턴을 생성할 때 호출된다. 이 메서드는 라우터가 관리하는 모든 뷰셋을 순회하며 각 뷰셋에 대한 URL 패턴을 생성한다. 이 예제에서는 각 뷰셋에 대해 list, retrieve, create, update, partial_update, destroy 액션에 대한 URL 패턴을 생성한다.


      - get_default_basename: 이 메서드는 라우터가 뷰셋을 등록할 때 호출된다. 이 메서드는 뷰셋을 등록할 때 basename 인자가 명시적으로 주어지지 않은 경우에 호출되며, 뷰셋의 모델 클래스 이름을 소문자로 변환하여 basename으로 사용한다.

 

      - 위의 코드를 실행하면 다음과 같은 URL 패턴이 생성된다.

         - /users/ - User 리스트를 보여주는 뷰 (GET), 새 User를 생성하는 뷰 (POST)

         - /users/{pk}/ - 특정 User의 상세 정보를 보여주는 뷰 (GET), 특정 User를 업데이트하는 뷰 (PUT, PATCH), 특정 User를 삭제하는 뷰 (DELETE)

 

 4. Third Party Packages

   1) DRF Nested Routers

      - drf-nested-routers 패키지는 중첩된 리소스를 다루기 위한 라우터와 관계 필드를 제공한다. 이 패키지를 사용하면 중첩된 URL 구조를 쉽게 다룰 수 있다. 예를 들어, 특정 사용자의 모든 게시글을 가져오는 등의 작업을 수행할 수 있다.

         - 참고 : https://github.com/alanjds/drf-nested-routers

 

      - 예시

         - /users/ : 모든 사용자를 보여주는 뷰
         - /users/{user_id}/ : 특정 사용자의 상세 정보를 보여주는 뷰
         - /users/{user_id}/posts/ : 특정 사용자의 모든 게시글을 보여주는 뷰
         - /users/{user_id}/posts/{post_id}/ : 특정 사용자의 특정 게시글의 상세 정보를 보여주는 뷰

 

   2) ModelRouter (wq.db.rest)

      - wq.db 패키지는 DefaultRouter를 확장하여 register_model() API를 제공하는 고급 ModelRouter 클래스(와 단일 인스턴스)를 제공한다. Django의 admin.site.register와 마찬가지로, rest.router.register_model에 필요한 유일한 인자는 모델 클래스다. URL 접두사, 직렬화기, 뷰셋에 대한 합리적인 기본값은 모델과 전역 구성에서 추론된다.

         - 참고 : https://wq.io/wq.db/

      - 이는 개발자에게 편의성을 제공하며, 간단한 API 라우팅을 구성할 때 반복적인 작업을 줄여준다. wq.db를 사용하면 Django 모델에 기반한 RESTful API를 효과적으로 구축하고 관리할 수 있다.

from wq.db import rest
from myapp.models import MyModel

rest.router.register_model(MyModel)

 

      - 기존 방식

# views.py
from rest_framework import viewsets
from .models import User

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

# urls.py
from rest_framework.routers import DefaultRouter
from .views import UserViewSet

router = DefaultRouter()
router.register(r'users', UserViewSet)

urlpatterns = router.urls

 

      - 위의 코드에서는 User 모델에 대한 뷰셋(UserViewSet)을 정의하고, 이를 DefaultRouter를 사용하여 URL에 연결한다. 이를 통해 '/users/' 경로로 User 모델에 대한 CRUD API를 제공하게 된다.

      - 하지만 wq.db의 ModelRouter를 사용하면, 이러한 과정을 좀 더 간단하게 처리할 수 있다. ModelRouter는 모델 클래스만을 인자로 받아, 해당 모델에 대한 뷰셋과 URL을 자동으로 생성해준다.

# routers.py
from wq.db import rest
from .models import User

rest.router.register_model(User, fields="__all__")

 

      - 참고

         - rest.router.register_model(User, fields='__all __ ')는 기본적으로 id가 참조 필드로 사용된다. 

         - rest.router.register_model(User, fields='__all__')를 사용하면, wq.db는 Django REST framework의 ModelViewSet을 기반으로 User 모델에 대한 기본 CRUD(Create, Read, Update, Delete) API를 자동으로 생성한다. 이는 모델의 모든 필드(__all__)를 사용하며, 별도의 뷰를 작성할 필요가 없다는 것이다.

 

   3) DRF-extensions

      - DRF-extensions 패키지는 중첩 뷰셋 생성을 위한 라우터와 커스터마이징 가능한 엔드포인트 이름을 가진 컬렉션 수준 컨트롤러를 제공한다.

         - 참고 : https://chibisov.github.io/drf-extensions/docs/

pip install drf-extensions
# serializers.py
from rest_framework import serializers
from .models import User, Post

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'
# urls.py
from rest_framework_extensions.routers import NestedRouter
from .views import UserViewSet, PostViewSet

router = NestedRouter()
users_router = router.register(r'users', UserViewSet)

# Nest the PostViewSet under the UserViewSet
users_router.register(r'posts', PostViewSet, basename='user-posts', parents_query_lookups=['user'])

urlpatterns = router.urls

 

      - 이 설정을 통해 다음과 같은 URL 패턴이 생성된다.
         - /users/: 모든 사용자를 조회하거나 새 사용자를 생성한다.

         - /users/{user_id}/: 특정 사용자의 상세 정보를 조회하거나 수정하거나 삭제한다.
         - /users/{user_id}/posts/: 특정 사용자의 모든 게시글을 조회하거나 새 게시글을 생성한다 .

         - /users/{user_id}/posts/{post_id}/: 특정 사용자의 특정 게시글의 상세 정보를 조회하거나 수정하거나 삭제한다 .

 

   4) DRF Nested Routers vs DRF-extensions

      - DRF-extensions와 DRF Nested Routers는 모두 Django REST Framework를 위한 서드파티 패키지로, 중첩된 라우팅을 지원한다. 그러나 두 패키지는 몇 가지 차이점을 가지고 있다.

      - 기능의 범위: DRF-extensions는 중첩된 라우팅뿐만 아니라 다양한 기능을 제공한다. 예를 들어, 부분적인 업데이트를 위한 PATCH 메서드 지원, 기본적인 뷰 또는 뷰셋 설정을 위한 믹스인, 향상된 페이징 등의 기능을 제공한다. 반면에, DRF Nested Routers는 주로 중첩된 라우팅 기능에 초점을 맞추고 있다.


      - 사용 방법: 두 패키지 모두 중첩된 라우팅을 제공하지만, 사용 방법에는 약간의 차이가 있다. DRF Nested Routers는 SimpleRouter 또는 DefaultRouter를 확장하여 NestedSimpleRouter와 NestedDefaultRouter를 제공하며, 이를 통해 중첩된 라우팅을 구현한다. 반면에, DRF-extensions는 NestedRouter를 제공하며, 이를 통해 중첩된 라우팅을 구현한다.


      - 커뮤니티 지원: DRF-extensions는 커뮤니티에서 더 넓게 사용되고 있으며, 문서화도 잘 되어 있다. 이에 비해 DRF Nested Routers는 사용자 수가 적고, 문서화가 상대적으로 덜 되어 있다.


      - 이러한 차이점들 때문에, 어떤 패키지를 사용할지는 프로젝트의 요구 사항에 따라 결정해야 한다. 중첩된 라우팅 외에도 다양한 기능을 필요로 하면 DRF-extensions를, 중첩된 라우팅에만 초점을 맞추고 싶으면 DRF Nested Routers를 사용하는 것이 좋을 수 있다.

 

 - 공식 사이트 문서 : https://www.django-rest-framework.org/api-guide/routers/#routers

 

Routers - Django REST framework

 

www.django-rest-framework.org