[DRF] 공식 문서 - Routers 정리
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
- 참고: 하이퍼링크된 시리얼라이저와 네임스페이싱을 함께 사용하는 경우, 시리얼라이저의 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
- 라우터는 슬래시와 점 문자를 제외한 모든 문자를 포함하는 조회 값과 일치한다. 더 제한적인 (또는 관대한) 조회 패턴을 위해, 뷰셋의 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