I have a model named Article and a few api views for it. They are divided for diffrent purposes (for example ArticleUpdateAPI class for UPDATE http method, ArticleDeleteAPI for DELETE method etc). In urls.py they are separated to diffrent endpoints (aritcle/pk/update, /article/pk/delete etc).
As I know, it's not good practice to build endpoint like this, so I want to bind them to single url and use diffrent classes for handling diffrent http methods. Is it possible and how? Examples are below
ArticleAPI.py
class ArticlePostAPI(generics.CreateAPIView):
serializer_class = ArticleSerializer
permission_classes = [
permissions.IsAuthenticatedOrReadOnly
]
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({
"comment": CommentSerializer.data
}, status=201)
class ArticleRetrieveAPI(generics.RetrieveAPIView):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
permission_classes = [
permissions.AllowAny
]
class ArticleListAPI(generics.ListAPIView):
serializer_class = ArticleSerializer
queryset = Article.objects.order_by('number', 'headline')
permission_classes = [
permissions.AllowAny
]
class ArticleUpdateAPI(generics.UpdateAPIView):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
permission_classes = [
permissions.IsAuthenticated
]
lookup_field = 'pk'
def update(self, request, *args, **kwargs):
instance = self.get_object()
if request.user != instance.author:
return Response({
"errors": "Logged in user and author must be same"
}, status=403)
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
urls.py
urlpatterns = [
...
# Article API
path('article/post/', ArticlePostAPI.as_view(), name='article_creation'),
path('article/<int:pk>/', ArticleRetrieveAPI.as_view(), name='article_retrieve'),
path('article/', ArticleListAPI.as_view(), name='article_list'),
path('article/<int:pk>/update/', ArticleUpdateAPI.as_view(), name='article_update'),
]
CodePudding user response:
Use ModelViewSet
for simplifying it.
Using this you can perform all http method actions with a single url and single view.
from rest_framework import viewsets
class ArticleView(viewsets.ModelViewSet):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
permission_classes = [permissions.AllowAny]
urls.py
router = DefaultRouter()
router.register(r'articles', views.ArticleView, basename='articles')
here
GET - /articles/ - gives list of all articles
GET - /articles/id/ - gives one object
POST - /articles/ - creates an article
PUT - /articles/id/ - updates an article
PATCH - /articles/id/ - partially updates an article
DELETE - /articles/id/ - deletes an article