[DRF] 중첩 url을 만들어 보자 : drf-nested-routers
- 이 포스팅은 다음 블로그의 정보를 기반으로 작성한다. drf-nested-routers와 관련된 항목에 버그가 있어 수정을 한다.
- 참고 : https://jaeseo0519.tistory.com/114
1. 중첩 url (nested url)
- 만약 다음과 같은 database가 있다고 가정한다.
- 우리가 원하는 시나리오는 다음과 같다.
- 특정 id의 pet 테이블을 참조하는 특정 cycle 정보이다.
- 만들고자 하는 url은 다음과 같다.
/api/pets/{pet_id}/cycles/{cycle_id}/
- 자동으로 생성되는 ModelViewSet 기반의 router는 자동 생성으로 위와 같은 중첩 url을 생성하지 못한다.
- 직접 as_view를 이용해 아래와 같이 url을 만들어줘야 한다.
# Get list of cycles in a Pet
url(r'^pets/(?P<pet_pk>\d+)/cycles/?$',
views.CycleViewSet.as_view({'get':'list'}), name='pet-cycle-list')
# Get deatil of a cycle in a Pet
url(r'^pets/(?P<pet_pk>\d+)/cycles/(?P<pk>\d+)/?$',
views.CycleViewSet.as_view({'get':'retrieve'}), name='pet-cycle-detail')
class CycleViewSet(viewsets.ModelViewSet):
"""Viewset of cylce"""
queryset = Cycle.objects.all().select_related(
'pet'
).prefetch_related(
'regular_cycle'
)
serializer_class = CycleSerializer
2. drf-nested-routers 를 사용해 구현하기
- 참고 : https://github.com/alanjds/drf-nested-routers
from rest_framework_nested import routers
router = SimpleRouter()
router.register('pets', views.PetViewSet)
cycle_router = routers.NestedSimpleRouter(
router,
r'pets',
lookup='pet'
)
cycle_router.register(
r'cycle',
views.CycleViewSet,
basename='pet-cycle'
)
app_name = 'pet'
urlpatterns = [
path('', include(router.urls)),
path('', include(cycle_router.urls)),
]
- lookup='pet': 이 매개변수는 상위 리소스(이 경우 'pets' 리소스)를 조회하는 데 사용될 키워드 인수를 지정합니다. 즉, 중첩된 라우터에 대한 뷰 또는 직렬 변환기를 정의할 때 함수 기반 뷰 또는 클래스 기반 뷰에서 상위 리소스에 대한 변수 이름으로 'pet'을 사용하게 됩니다.
- 예를 들어 CycleViewSet에서 상위 'pet' 리소스에 액세스해야 하는 메서드가 있는 경우 pet을 키워드 인수로 사용할 수 있습니다.
class CycleViewSet(viewsets.ModelViewSet):
# ...
def list(self, request, pet, *args, **kwargs):
# Access the parent 'pet' resource using the 'pet' parameter
# Your logic here
pass
* 예시로 사용된 코드에 queryset과 get_queryset이 같이 있어서 혼란스러웠다. 두 코드가 정의되면 get_queryset만 사용된다.
- 하지만 get_queryset을 정의하지 않았다면, queryset의 캐시 문제로 create와 update에서 갱신된 데이터가 queryset에 반영되지 않는다는 문제가 있다.
- 해당 문제를 chatbot에게 여러 방법으로 질문하여 오류를 거르고 얻은 결과로 다음과 같은 방법이 있다.
- save 이후 self.get_queryset()을 호출하면 갱신된 모델 정보를 가져와 queryset을 갱신한다.
- 해당 방법은 코드로 테스트하지 않았기에 확인이 필요하다.
class MyModelViewSet(viewsets.ModelViewSet):
serializer_class = MyModelSerializer
queryset = MyModel
def create(self, request, *args, **kwargs):
instance = MyModel.objects.create(**request.data)
instance.save()
# Reevaluate the queryset to include the changes
queryset = self.get_queryset()
return Response({'message': 'Object created successfully'})
- 참고 :
https://jaeseo0519.tistory.com/114
https://kimdoky.github.io/django/2018/07/08/drf-Routers/
'Django REST Framework > DRF 일반' 카테고리의 다른 글
[DRF] 공식 문서 - views의 정리 3 - CBV(Generic views) (0) | 2024.01.10 |
---|---|
[DRF] 공식 문서 - views의 정리 2 - CBV(APIView) (0) | 2024.01.08 |
[DRF] 공식 문서 - views의 정리 1 - FBV(api_view) (0) | 2024.01.08 |
[DRF] CSRF, csrf_exempt 에 대한 정리. (0) | 2024.01.07 |
[DRF] settings.py 자주 사용 되는 구성 옵션의 정리 (0) | 2024.01.05 |
댓글