Django restframework加Vue打造前后端分离的网站(三)在View中自定义API
前一篇写了新建一个简单的api,在这篇会记录一下在view中写自定义api的4种方法。
比如我们还是用上一篇的project对象,需要能展示project列表和具体一个project信息,project可以新加、修改,但不应该被删除掉。
第一种
通用型,适用于有model的对象,使用ModelViewSet,会包含所有可用的api方法。如果需要自定义比如禁用delete,则可以重写这个方法。
from .models import Project
from .serializers import ProjectSerializer
from rest_framework import viewsets
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
# 如果想禁用某一个方法,可以类似如下,但不如用generics.RetrieveUpdateAPIView
def destroy(self, request, *args, **kwargs):
return Response({"message": "delete action is not allowed", "code": "200"}, status=status.HTTP_200_OK)
使用这种方法,不需要在app内添加url.py。但是在项目的url.py中需要加入下面几行
from projects.views import ProjectViewSet
router = routers.DefaultRouter()
router.register(r'projects', ProjectViewSet)
urlpatterns = [
path('api/', include(router.urls)),
...
]
第二种
使用APIView。这种的代码量会多一点,但如果引入了第三方比如支付相关的,没有具体的业务对象在model中定义,那么这种会比较适合一点。
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class ProjectList(APIView):
# 定义 GET 请求的方法,内部实现相同 @api_view
def get(self, request):
projects = Project.objects.all()
serializer = ProjectSerializer(projects, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
# 定义 POST 请求的方法
def post(self, request):
serializer = ProjectSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ProjectDetail(APIView):
def get_object(self, pk):
try:
return Project.objects.get(pk=pk)
except Project.DoesNotExist:
raise Http404
def get(self, request, pk):
project = self.get_object(pk)
serializer = ProjectSerializer(project)
return Response(serializer.data)
def put(self, request, pk):
project = self.get_object(pk)
serializer = ProjectSerializer(project, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
## to permit delete action or not
# def delete(self, request, pk):
# project = self.get_object(pk)
# project.delete()
# return Response(status=status.HTTP_204_NO_CONTENT)
除了第一种,剩下的都需要添加app内url.py,并修改项目url.py。
# url.py in app
from django.urls import path
from . import views
urlpatterns = [
path('', views.ProjectList.as_view(), name='project_list'),
path(r'<int:pk>/', views.ProjectDetail.as_view(), name='project_detail'),
]
# url.py in your web project
urlpatterns = [
...
path('api/projects/', include('projects.urls')),
...
]
第三种
使用mixins。继承不同的mixins便可以获得不同的http方法,比如CreateModelMixin可以使用post,UpdateModelMixin可以使用put。
from rest_framework import mixins
from rest_framework import generics
class ProjectList(mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
generics.GenericAPIView):
# 指定列表
queryset = Project.objects.all()
# 指定序列化类
serializer_class = ProjectSerializer
def get(self, request, *args, **kwargs):
# list 方法继承 ListModelMixin 而来
return self.list(self, request, *args, **kwargs)
def post(self, request, *args, **kwargs):
# create 方法继承 CreateModelMixin 而来
return self.create(self, request, *args, **kwargs)
# detail 视图通过 mixins 和 generics 改造
class ProjectDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(self, request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(self, request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(self, request, *args, **kwargs)
第四种
只使用generics,代替了mixins的功能。这种代码量最少。比如我希望包含get/put/delete则可以继承generics.RetrieveUpdateDestroyAPIView;如果我只希望有get/put不包含delete,那么可以继承generics.RetrieveUpdateAPIView。
from rest_framework import generics
class ProjectList(generics.ListCreateAPIView):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
# class ProjectDetail(generics.RetrieveUpdateDestroyAPIView):
class ProjectDetail(generics.RetrieveUpdateAPIView):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
不得不说,django restframework实在是好用方便。