视图家族之两个视图基类
视图家族之两个视图基类
一、APIView
rest_framework.views.APIView
APIView
是REST framework提供的所有视图的基类,继承自Django的View
父类。
APIView
与View
的不同之处在于:
- 传入到视图方法中的是REST framework的
Request
对象,而不是Django的HttpRequeset
对象,对request进行二次封装; - 视图方法可以返回REST framework的
Response
对象,视图会为响应数据设置(render)符合前端要求的格式; - 任何
APIException
异常都会被捕获到,并且处理成合适的响应信息; - 在进行dispatch()分发前,会对请求进行请求、响应、渲染、异常、解析、三大认证;
- 重写as_view禁用了csrf认证;
支持定义的属性
- authentication_classes 列表或元祖,身份认证类
- permissoin_classes 列表或元祖,权限检查类
- throttle_classes 列表或元祖,流量控制类
在APIView
中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
举例:
from rest_framework.views import APIView
from rest_framework.response import Response
# url(r'^books/$', views.BookListView.as_view()),
class BookListView(APIView):
def get(self, request):
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
return Response(serializer.data)
二、GenericAPIView[通用视图类]
rest_framework.generics.GenericAPIView
继承自APIVIew
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
-
属性:
- serializer_class 指明视图使用的序列化器(自定义的类序列化器)
-
方法:
-
get_serializer_class(self)
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回
serializer_class
,可以重写,例如:def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer
-
get_serializer(self, *args, **kwargs)
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
- request 当前视图的请求对象
- view 当前请求的类视图对象
- format 当前请求期望返回的数据格式
-
提供的关于数据库查询的属性与方法
-
属性:
- queryset 指明使用的数据查询集
-
方法:
-
get_queryset(self)
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回
queryset
属性,可以重写,例如:def get_queryset(self): user = self.request.user return user.accounts.all()
-
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在视图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()), class BookDetailView(GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self, request, pk): book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象 serializer = self.get_serializer(book) return Response(serializer.data)
-
其他可以设置的属性
- pagination_class 指明分页控制类
- filter_backends 指明过滤控制后端
三、总结
-
APIView视图
- 继承Django原生的as_view()视图函数,在View中的as_view()方法主要是完成将请求方式(get)与视图类的同名方法(get)建立对应的请求方法映射,来完成对应的请求响应,APIView中不同如下
- APIView继承了原生Django的View视图类,与View不同之处如下
- 具有View的功能, 重写了as_view方法禁用了csrf认证,多了一堆的类属性,可以完成视图类的局部配置
- drf中as_view中对原生wsgi中的request请求进行了二次封装,不是Django原生的HttpRequest对象,但是他也具有他的所有功能,在二次封装的同时还完成了数据的解析
- drf中as_view中对原生wsgi中的response请求进行了二次封装,不是Django原生的response对象,在二次封装的同时还完成了数据的渲染格式
- 在dispatch中完成了所有的异常的捕获,并做出对应的响应
- 在进行dispatch分发之前会对请求进行身份认证、权限认证、流量的控制
- 在dispatch中完成了请求、响应、渲染、异常、解析、三大认证
-
GenericAPIView视图
-
GenericAPIView类继承了APIView类具有他的全部功能,间接的继承了View类,主要增加 了主要增加了序列化器和数据库的查询方法,作用为下面Mixin扩展类执行提供方法和属性的支持,通常搭配Mixin扩展类一起使用,实现六大功能
-
提供了两个属性
- queryset将orm查找的结果集给他:queryset = models.Student.objects.all()
- serializer_class 将自己自定义的序列化类给他:serializer_class = StudentSerializers
-
四个方法,都依赖于上面的两个属性
- get_object(): 获取orm查询的类对象 模型类,Student object
- get_queryset(): orm对象数据中的结果集, models.Student.objects.all() <QuerySet [<Student: Student object>, <Student: Student object>]>
- get_serializer_class(): 获取序列化类,自定义的序列化类
- get_serializer(): 获取序列化类产生的结果
-
eg:
class StudentGenericAPIView(GenericAPIView): """ 群查序列化 1) student_list_obj = models.Student.objects.all()将这一句话转换了两句话,看源码 设置类属性GenericAPIView中的queryset的值 queryset = models.Student.objects.all() 获取orm查询的对象结果 stu_query = self.get_queryset() 2) 将一句话变成了两句话 student_list = StudentSerializers(student_list_obj, many=True) 设置自己序列的类 serializer_class = StudentSerializers 获取序列化类的结果 stu_ser = self.get_serializer(stu_query, many=True),调用了get_serializer_class获取序列化的类 把原先可以一步完成的事情分成了两部分 """ queryset = models.Student.objects.all() serializer_class = StudentSerializers def get(self, request, *args, **kwargs): print(self.get_object()) print(self.get_queryset()) print(self.get_serializer()) print(self.get_serializer_class()) stu_query = self.get_queryset() stu_ser = self.get_serializer(stu_query, many=True) return APIResponse(results=stu_ser.data)
-