# views.py
from rest_framework import viewsets
from rest_framework.response import Response
class PostViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Post.objects.all()
serializer = PostSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk):
queryset = Post.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = PostSerializer(user)
return Response(serializer.data)
# urls.py
router = DefaultRouter()
router.register('post', PostViewSet, basename='post')
router.urls
-> ModelViewSet을 통해 간결하게 구현할 수 있다.
from rest_framework import generics
class PostListAPIView(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
viewsets.ReadOnlyModelViewSet
list 지원 -> 1개의 URL
detail 지원 -> 1개의 URL
viewsets.ModelViewSet
list/create 지원 -> 1개의 URL
detail/update/partial_update/delete 지원 -> 1개의 URL
from rest_framework import viewsets
class PostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
post_list = PostViewSet.as_view({
'get': 'list',
})
post_detail = PostViewSet.as_view({
'get': 'retrieve',
})
어떠한 method가 왔을 때, 어떠한 함수를 호출해주겠다라는 의미
get method 요청이 오면, list 함수를 호출
get method 요청이 오면, retrieve 함수를 호출
그래서 각각 다른 urls.py에 하나하나 다 써서 매핑해야됨.
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('post', views.PostViewSet)
urlpatterns = [
path('', include(router.urls)),
]
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('post', views.PostViewSet)
urlpatterns = [
path('', include(router.urls)),
]
[
<URLPattern '^post/$' [name='post-list']>,
<URLPattern '^post\.(?P<format>[a-z0-9]+)/?$' [name='post-list']>,
<URLPattern '^post/(?P<pk>[^/.]+)/$' [name='post-detail']>,
<URLPattern '^post/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='post-detail']>,
<URLPattern '^$' [name='api-root']>,
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
]
from rest_framework.decorators import action
class PostModelViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
@action(detail=False, methods=['GET'])
def public(self, request):
qs = self.queryset.filter(is_public=True)
serializer = self.get_serializer(qs, many=True)
return Response(serializer.data)
@action(detail=True, methods=['PATCH'])
def set_public(self, request, pk):
instance = self.get_object()
instance.is_public = True
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
action이라는 데코레이터가 있다.
위에 함수에서 public url로 접근하면 공개된 게시글만 불러온다.
set_public은 public으로 변경해주는 함수.
여기서 detail=False는 공개된 게시글들을 전부 불러오는것이기에 detail이 아닌 list이다.
set_public은 특정 게시글을 공개 게시글로 바꾸는 것이기 때문에 detail=True이다.
그래서 detail을 통해 list쪽 url을 탈 것이냐, detail쪽 url을 탈 것이냐 판가름이 난다.
[
...
<URLPattern '^post/public/$' [name='post-public']>,
<URLPattern '^post/public\.(?P<format>[a-z0-9]+)/?$' [name='post-public']>,
...
<URLPattern '^post/(?P<pk>[^/.]+)/set_public/$' [name='post-set-public']>,
<URLPattern '^post/(?P<pk>[^/.]+)/set_public\.(?P<format>[a-z0-9]+)/?$' [name='post-set-public']>,
...
]
쉘> http PATCH http://도메인/post/10/set_public/
- 위의 함수를 적용시켰을때 해당 도메인으로 이동하면 공개 게시글로 적용
쉘> http PATCH http://도메인/post/10/ is_public=true
- 만약 위의 함수를 적용시키지 않으면 위의 명령어를 쉘에 작성해서 직접 공개 게시글로 만들어줄 수 있다.