Resouce routing을 사용하면 특정 resource controller에 대한 모든 공통 경로를 신속하게 선언할 수 있습니다. index에 대해 별도로 경로를 선언하는 대신 유용한 경로는 한 줄의 코드로 경로를 선언합니다.
-Ruby on Rails Documentation
Rails와 같은 일부 웹 프레임워크는 들어오는 requests를 처리하는 login에 애플리케이션의 URL을 매핑하는 방법을 자동으로 결정하는 기능을 제공합니다.
REST framework는 Django에 대한 자동 URL routing을 추가하고 view logic을 URL 세트에 연결하는 간단하고 빠르며 일관된 방법을 제공합니다.
Usage
SimpleRouter을 사용하는 간단한 방법
from rest_frmamework import routers
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accoutns', AccountViewSet)
urlpatterns = router.urls
Register() method에는 두 가지 필수 인자가 있습니다.
- prefix - 이 경로 set에 사용할 URL 접두사
- viewset - viewset class입니다
선택적 추가 인수
- basename - 생성된 URL에 사용할 기본 이름입니다. 설정되지 않은 경우 view set의 queryset 속성을 기반으로 basename을(있는 경우) 설정합니다. viewset에 queryset 속성이 포함되어 있지 않으면 viewset을 등록할 때 basename을 설정해야 합니다.
위의 예에서 URL 패턴을 생성합니다.
- ^users/$ 'user-list'
- ^users/{pk}/$ 'user-detail'
- ^accounts/$ 'account-list'
- ^accounts/{pk}/$ 'account-detail'
참고: basename 인수는 view 이름 패턴의 초기 부분을 지정하는데 사용됩니다.
일반적으로 basename 인수를 지정할 필요가 없지만 사용자 정의 get_queryset method를 정의한 viewset이 있는 경우 viewset에 아마 .queryset attribute가 없을 것 입니다. register을 등록하려고 하면 아래의 에러문을 만날 것입니다.
'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
이것은 model 이름에서 자동으로 결정될 수 없으므로 viewset을 등록할 때 basename 인수를 명시적으로 설정해야 합니다.
Using incldue with routers
router instance의 .ruls 속성은 URL 패턴의 표준 목록입니다. 이러한 URL을 포함하는 방법에는 다양한 스타일이 있습니다.
예를 들어 기존 views에 router.urls를 추가 할 수 있습니다.
router = routers.SimpleRouter()
router.registser(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
]
urlpatterns += router.urls
또는 다음과 같이 Django의 include 기능을 사용할 수도 있습니다.
urlpatterns = [
path('forgot-password', ForgotPasswordFormView.as_view()),
path('', include(router.urls)),
]
애플리케이션 namespace와 함께 include를 사용할 수 있습니다.
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'))),
]
또는 애플리케이션 instance namespace와 함께
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
]
자세한 내용은 Django의 URL namespace 문서와 include API reference를 참조하세요
참고: hyperlinked serializer와 함께 namespace를 사용하는 경우 serilizer의 view_name의 매게변수가 namespace를 올바르게 반영하는지 확인해야 합니다. 위의 예에서 사용자 세부 정보 보기에 하이퍼링크된 serializer filed에 대해 view_name='app_name:user-detail'과 같은 매개변수를 포함해야 합니다.
자동 view_name 생성은 %(model_name)-detail과 같은 패턴을 사용합니다. 모델 이름이 실제로 충돌하지 않는 한 hyperlink serializer을 사용할 때 Django REST Framework 보기의 네임스페이스를 지정하지 않는 것이 더 나을 수 있습니다.
Routing for extra actions
viewset은 @action decorator로 method를 장식하여 routing을 위한 추가 작업을 표시할 수 있습니다.
이러한 추가 작업은 생성된 경로에 포함됩니다. 예를 들어 UserViewSet class에 set_password method가 있다고 가정하면
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 pattern: ^users/{pk}/set_password/$
- URL name: 'user-set-password'
기본적으로 URL pattenr은 method 이름을 기반으로하며, URL 이름은 ViewSet.basename과 - 로 연결된 method 이름의 조합입니다. 이러한 값 중 하나에 대해 기본값을 사용하지 않으려면 @action detoraotr에 url_path및 url_name 인수를 제공할 수 있습니다.
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 path: ^users/{pk}/change-password/$
- URL name: 'user-change_password'
API Guide
SimpleRouter
이 router에는 list, create, retrieve, update, partial_update destroy actions가 포함되어 있습니다. viewset은 @action decorator을 사용하여 routing 할 추가 method를 표시할 수 있습니다.
URL Style | HTTP MEthod | Action | URL Name |
{prefix}/ | GET | list | {basename}-list |
POST | create | ||
{prefix}/{url_path}/ | GET 또는 methods 인수로 지정 | @action(detail=False) decorated된 method | {basename}-{url_name} |
{prefix}/{lookup}/ | GET | retrieve | {basename}-detail |
PUT | update | ||
PATCH | partial_update | ||
DELETE | destroy | ||
{prefix}/{lookup}/{url_path}/ | GET 또는 methods 인수로 지정 | @action(detail=False) decorated된 method | {basename}-{url_name} |
기본적으로 SimpleRouter에서 생성된 URL에는 / 가 추가됩니다. 이 동작은 router을 instance화 할 때 trailing_slash 인수를 False로 설정하여 수정할 수 있습니다.
router = SimpleRouter(trailing_slash=False)
참고: use_regex_path=False는 Django 2.x 이상에서만 작동합니다. 이 기능은 2.0.0에 도입되었기 때문입니다.
router은 / 와 . 를 제외한 모든 문자가 포함된 조회 값을 일치시킵니다.보다 다양한 lookup pattern의 경우, path converters를 사용한다면 lookup_vlaue_converter에 lookup_value_regex 속성을 설정하세요. 예를 들어 유효한 UUID로 조회를 제한할 수 있습니다.
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_modle_id'
lookup_vlaue_regex = '[0-9a-f]{32}'
class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_uuid'
lookup_value_converter = 'uuid'
DefaultRouter
이 라우터는 SimpleRouter과 유사하지만 모든 목록에 대한 하이퍼링크가 포함된 response를 반환하는 기본 API route가 추가로 포함되어 있습니다. 또한 선택적 .json 스타일로 path를 생성합니다.
URL Style | HTTP Method | Action | URL Name |
[.format] | GET | automatically generated root view | api-root |
{prefix}/[.format] | GET | list | {basename}-list |
POST | create | ||
{prefix}/{lookup}/[.foramt] | GET 또는 methods 인수로 지정 | @action(detail=False) decorated된 method | {basename}-{url_name} |
{prefix}/{lookup}/[.foramt] | GET | retrieve | {basename}-detail |
PUT | update | ||
PATCH | partial_update | ||
DELETE | destroy | ||
{prefix}/{lookup}/{url_path}/[.foramt] | GET 또는 methods 인수로 지정 | @action(detail=False) decorated된 method | {basename}-{url_name} |
SimpleRouter과 마찬가지로 URL 경로의 /는 라우터를 인스턴스화 할때 trailing_slash arguments를 False해서 제거할 수 있습니다.
router = DefaultRouter(trailing_slash=False)
Custom Router
사용자 정의 router는 자주 사용하지는 않지만 API의 URL구성 방식에 대한 특정 요구 사항이 있는 경우 유용할 수 있습니다. 이렇게 하면 재사용 가능한 방식으로 URL구조를 캡슐화 할 수 있습니다
custom router을 구현하는 가장 쉬운 방법은 기존 router class중 하나를 하위 class로 만드는 것입니다. .routes attribute는 각 viewset에 매핑될 URL 패턴을 템플릿화 하는데 사용됩니다. .routes 속성은 튜플이라는 경로 이름의 목록입니다.
Route의 튜플에 대한 인수는 다음과 같습니다.
url: 라우팅할 URL을 나타내는 문자열입니다. 다음 형식 문자열이 포함될 수 있습니다.
- {prefix} - 이 path 집합에 사용할 URL 접두사 입니다.
- {lookup} - single instance와 일치하는데 사용되는 조회 필드 입니다.
- {trailing_slash} - trailing_slash 인수에 따라 '/' 또는 빈 문자열입니다.
mapping: HTTP 메서드 이름을 view method에 mapping 합니다.
name: reverse call에 사용되는 URL 이름입니다.
- {basename} - 생성된 URL 이름에 상요할 기본입니다.
initkwargs: view를 instance화할 때 전달되어야 하는 추가 인수 dict 입니다. Detail, basename 및 suffix 인수는 viewset 내부 검사를 위해 예약되어 있으며 탐색 가능한 API에서 view 이름 및 이동 경로 링크를 생성하는 데에도 사용됩니다.
Customzing dynamci routes
@action decorator가 routing 되는 방식을 사용자 정의 할 수 있습니다. .routes 목록에 튜플이라는 이름의 DynamicRoute를 포함하고 list-base 경로에 맞게 detail 인수를 설정합니다. 세부사항 외에도 DynamicRoute에 대한 인수는 다음과 같습니다.
url: routing 할 URL을 나타내는 문자열입니다. Route와 동일한 형식 문자열을 포함할 수 있으며 추가로 {url_path}형식 문자열을 허용합니다.
name: reverse 호출에 사용되는 URL의 이름입니다. 다음 형식 문자열이 포함될 수 있습니다.
- {basename} - 생성된 URL 이름에 사용할 기본입니다.
- {url_name} - @action에 제공된 url_name 입니다.
initkwargs: view를 instance화 할 때 전달되어야 하는 추가 인수 사전 입니다.
Example
다음 example에서는 list와 retrieve actions을 수행하고 trailing slash convention은 사용하지 않습니다.
from rest_framework.routers import Route, DynamicRoute, SimpleRouter
class CustomReadOnlyRouter(SimpleRouter):
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가 간단한 viewset을 생성하는 경로를 보겠습니다.
views.py:
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'
@action(detail=True)
def group_names(self, request, pk=None):
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
다음 mapping이 생성됩니다.
URL | HTTP Method | Action | URL Name |
/users | GET | list | user-list |
/users/{usernmame} | GET | retrieve | user-detail |
/users/{username}/gropup_names | GET | group_names | user-group-names |
.routes attribute를 설정하는 다른 예는 SimpleRouter class의 source code를 참조하세요
Advanced custom routers
완전한 custom 동작을 구현하려면 BaseRouter과 get_urls(self) method를 override override 할 수 있습니다. method는 등록된 viewset을 검사하고 url 패턴 리스트를 return 해야합니다. 등록된 prefix, viewset, basename은 self.registry 속성에 액세스해서 검사 할 수 있습니다. get_default_vasename(self, viewset) method를 override하거나 router에 viewset을 등록할 때 항상 basename을 명시적으로 설정할 수도 있습니다.
Third Party Packages
다음의 타사 패키지도 사용 가능합니다.
DRF Nested Routers
drf-nested-routers는 중첩된 리소스 작업을 위한 라우터 관계 필드를 제공합니다.
ModelRouter(sq.db.rest)
wq.db package는 Register_model() API를 사용해서 DefaultRouter을 확장하는 고급 ModelRouter class를 제공합니다. Django의 admin.site.register과 마찬가지로,. Rest.router.register_model에 필요한 유일한 인수는 모델 클래스 입니다. URL prefix, serializer, viewset에 대한 default값은 model 및 전역 구성에서 추론됩니다.
from wq.db import rest
from myapp.models import MyModel
rest.router.register_model(MyModel)
'Django > restframework' 카테고리의 다른 글
JWT (0) | 2024.04.24 |
---|---|
Restframework JWT 설정 (0) | 2024.01.29 |
Viewsets (2) | 2024.01.22 |
Generic views (0) | 2024.01.18 |
DRF docs API Guide Class-based Views (1) | 2024.01.15 |