1.两个基类
1.1 APIView
(1)APIView继承于Django的View,是REST framework提供的所有视图的基类,request参数不是Django的HttpRequeset,而是在此基础上进行了拓展,
request.data:即Django的request.POST和 request.FILES
request.query_params:即Django的request.GET
Response(需另外导入):任何APIException异常都会被捕获到
1.2 GenericAPIView
GenericAPIView继承于APIView,增加一些比较常用的通用支持方法,一般可搭配一个或多个Mixin扩展类使用
支持定义的属性 | 说明 |
---|---|
queryset | 查询集 |
serializer_class | 序列化器 |
lookup_field | 查询单一数据的过滤字段,默认是pk |
lookup_url_kwarg | 查询单一数据的参数关键字名称,默认与lookup_field相同 |
pagination_class | 分页控制类 |
filter_backends | 过滤控制后端 |
方法 | 说明 |
---|---|
get_queryset(self) | 获取查询集 |
get_object(self) | 获取单一模型类对象 |
get_serializer(self, *args, **kwargs) | 获取实例化的序列化器对象 |
get_serializer_class(self) | 获取序列化器类 |
以上方法一般配合定义的类属性使用,确保得到的是最新的结果(因为存在惰性和缓存)
举例
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from .models import BookInfo
from .serializers import BookInfoModelSerializer
# re_path(r'^books/$',views.BooksView.as_view()),
class BooksView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoModelSerializer
# 获取列表资源:GET /books/
def get(self,request):
books = self.get_queryset() # 即返回类属性的查询集
serializer = self.get_serializer(instance=books,many=True)
return Response(data=serializer.data)
# 新建单一资源:POST /books/
def post(self,request):
serializer = self.get_serializer(data=request.data)
if not serializer.is_valid():
return Response(data={
"errmsg":"参数错误"},status=400)
serializer.save()
return Response(data=serializer.data)
# re_path(r'^book/(?P<pk>\d+)/$',views.BookView.as_view())
class BookView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoModelSerializer
# lookup_field = 'pk' # 该类属性默认值就是'pk' —— 默认唯一过滤依据'pk'字段
# lookup_url_kwarg = lookup_field # 该类属性默认等于lookup_field —— 指定提取过滤字段值的分组名称
# 获取单一资源:GET /books/1/
def get(self,request, pk):
book = self.get_object() # 默认使用lookup_field参数来过滤queryset
serializer = self.get_serializer(instance=book)
return Response(data=serializer.data)
# 更新单一资源(全更新):PUT /books/1/
def put(self, request, pk):
book =self.get_object()
serializer = self.get_serializer(instance=book,data=request.data)
if not serializer.is_valid():
return Response(data={
"errmsg":"参数错误"},status=400)
serializer.save()
return Response(data=serializer.data)
# 更新单一资源(部分更新):PATCH /books/1/
def patch(self,request, pk):
book = self.get_object()
serializer = self.get_serializer(instance=book,data=request.data)
if not serializer.is_valid():
return Response({
"errmsg":"参数错误"},status=400)
serializer.save()
return Response(data=serializer.data)
# 删除单一资源:DELETE /books/1/
def delete(self,request,pk):
book = self.get_object()
book.delete()
return Response(data=None,status=204)
2.五个扩展类
扩展类 | 说明 |
---|---|
ListModelMixin | 提供self.list 方法,封装序列化多条模型类对象(列表数据) 返回的逻辑代码 |
CreateModelMixin | 提供self.create 方法,封装反序列化新建单一对象的逻辑代码 |
RetrieveModelMixin | 提供self.retrieve 方法,封装序列化返回单一资源的逻辑代码 |
UpdateModelMixin | 提供self.update 方法,封装反序列化全更新(全校验)单一资源的逻辑代码提供 self.partial_update 方法,封装反序列化部分更新(部分校验)单一资源的逻辑代码 |
DestroyModelMixin | 提供self.destroy 方法,封装反序列化删除单一资源的逻辑代码 |
还是上面的代码,继承GenericAPIView,感觉写法太啰嗦了,我们可以继承五大拓展类,直接return封装好的方法,大大简化代码,改写如下
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
DestroyModelMixin
from .models import BookInfo
from .serializers import BookInfoModelSerializer
# re_path(r'^books/$',views.BooksView.as_view()),
class BooksView(ListModelMixin,CreateModelMixin,GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoModelSerializer
# 获取列表资源:GET /books/
def get(self,request):
return self.list(request)
# 新建单一资源:POST /books/
def post(self,request):
return self.create(request)
# re_path(r'^book/(?P<pk>\d+)/$',views.BookView.as_view())
class BookView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoModelSerializer
# lookup_field = 'pk' # 该类属性默认值就是'pk' —— 默认唯一过滤依据'pk'字段
# lookup_url_kwarg = lookup_field # 该类属性默认等于lookup_field —— 指定提取过滤字段值的分组名称
# 获取单一资源:GET /books/1/
def get(self,request, pk):
return self.retrieve(request,pk)
# 更新单一资源(全更新):PUT /books/1/
def put(self, request, pk):
return self.update(request,pk)
# 更新单一资源(部分更新):PATCH /books/1/
def patch(self,request, pk):
return self.partial_update(request,pk)
# 删除单一资源:DELETE /books/1/
def delete(self,request,pk):
return self.destroy(request,pk)
3.五个子类视图
视图 | 说明 |
---|---|
ListAPIView | 序列化返回列表资源 提供 self.get 视图方法,内部调用拓展视图self.list 方法 |
CreateAPIView | 反序列化新建单一资源 提供 self.post 视图方法,内部调用拓展视图self.create 方法 |
RetrieveAPIView | 序列化返回单一资源 提供 self.get 视图方法,内部调用拓展视图self.retrieve 方法 |
UpdateAPIView | 反序列化更新单一资源 提供 self.put 视图方法,内部调用拓展视图self.update 方法 提供 self.patch 视图方法,内部调用拓展视图self.partial_update 方法 |
DestroyAPIView | 反序列化删除单一资源 提供 self.delete 视图方法,内部调用拓展视图self.destroy 方法 |
还是上面的代码,继承五大扩展类的,但是代码还不够简洁,我们还可以把它进一步精简,就是通过继承五个子类视图省略用于路由的请求方法
from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, \
DestroyAPIView
from .models import BookInfo
from .serializers import BookInfoModelSerializer
# 原则:一类资源,尽可能使用一个类视图封装增删改查接口;
# 结论:Mixin几个拓展类中提供的方法定义是如何视图函数定义 —— 可以用来进行路由映射
# re_path(r'^books/$',views.BooksView.as_view()),
class BooksView(CreateAPIView,ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoModelSerializer
# re_path(r'^book/(?P<pk>\d+)/$',views.BookView.as_view())
class BookView(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoModelSerializer
4.视图集
视图 | 说明 |
---|---|
ViewSetMixin | 重写self.as_view()函数,传入字典指定请求方式映射的视图函数 |
ViewSet | 继承ViewSetMixin和APIView |
ModelViewSet | 继承五大拓展类和GenericAPIView |
GenericViewSet | 继承ViewSetMixin和GenericAPIView |
ReadOnlyModelViewSet | 继承RetrieveModelMixin、ListModelMixin和GenericAPIView;提供只读接口 |