写在前面-->视图回顾:
Django视图的使用
-
Django的函数视图:
注意这里的 request 和 response, 获取数据很麻烦, 返回数据很麻烦
# 一个函数视图处理多种请求, 代码可读性与复用性都不佳。 # 视图函数:注册 # url(r'^register/$', views.register, name='register'), def register(request): """处理注册""" # 获取请求方法,判断是GET/POST请求 if request.method == 'GET': # 处理GET请求,返回注册页面 return render(request, 'register.html') else: # 处理POST请求,实现注册逻辑 return HttpResponse('这里实现注册逻辑')
注意: render(request对象, 模板文件路径, 模板数据字典)
使用render,记得 第一个参数 需要写<request>
-
Django的类视图:
敲黑板: 这里 我们 第一次见到了 View
要明确的是:
- 类视图View 还是 使用的 Django的 原生 Request 和 Response, 所以 不好用
- 类视图View, 提供了各种 get(), post(), put() , delete() 函数方法
# 使用: 将视图对应的 <不同请求方式> 以类中的 <不同方法> 来区别定义。 # 类视图:注册 # url(r'^register/$', views.RegisterView.as_view(), name='register'), from django.views.generic import View class RegisterView(View): """类视图:处理注册""" def get(self, request): """处理GET请求,返回注册页面""" return render(request, 'register.html') def post(self, request): """处理POST请求,实现注册逻辑""" return HttpResponse('这里实现注册逻辑')
一、APIView类视图
1.1 APIView
是DRF对View
的扩展
与View区别:
Request
对象 不一样
Response
对象 不一样任何
APIException
异常都会被捕获到,并且处理成合适的响应信息;在进行
dispatch()分发前
,会对请求进行身份认证、权限检查、流量控制。继承了 View 的 get(), post(), put() , delete() 函数方法
-
关于
Request
对象-
其将解析为
类字典对象
保存到Request对象中 -
获取Request数据
-
request.data
1) 包含了对POST、PUT、PATCH请求方式解析后的数据(增加-更新-局部更新)
2) 相当于 request.body (json数据获取) + request.POST (post.form表单数据获取)
-
request.query_params
与Django标准的
request.GET
相同 -
-
关于
Response
对象Response会根据请求头中的
Accept
(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。- 构造方式
Response(data, status=None, template_name=None, headers=None, content_type=None) # data: 只需传递python的内建类型数据即可, 不可是对象; # status: 状态码,默认200; # template_name: 模板名称,如果使用HTMLRenderer时需指明; # headers: 用于存放响应头信息的字典; # content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
- 状态码
# 1)信息告知 - 1xx # 2)成功 - 2xx # 3)重定向 - 3xx # 4)客户端错误 - 4xx # 5)服务器错误 - 5xx
1.2 支持定义的属性
- authentication_classes列表或元祖,身份认证类
- permissoin_classes列表或元祖,权限检查类
- throttle_classes列表或元祖,流量控制类
1.3 代码
# 在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类视图
2.1 GenericAPIView
是对APIView
的扩展
- 继承自
APIVIew
,
- 增加了对于列表视图和详情视图可能用到的通用支持方法。
- 搭配一个或多个Mixin扩展类。
- 需要实现queryset属性或者重写get_queryset方法
2.1 属性:
- 列表视图与详情视图通用:
- queryset列表视图的查询集
- serializer_class视图使用的序列化器
- 列表视图使用:
- pagination_class分页控制类
- filter_backends过滤控制后端
- 详情页视图使用:
-
lookup_field查询单一数据库对象时使用的条件字段,默认为'
pk
' - lookup_url_kwarg查询单一数据时URL中的参数关键字名称,默认与look_field相同
-
lookup_field查询单一数据库对象时使用的条件字段,默认为'
2.2 方法:
-
列表视图与详情视图通用:
-
get_queryset(self)
返回视图使用的查询集,是列表视图与详情视图获取数据的基础,默认返回
queryset
属性,可以重写,例如:def get_queryset(self): user = self.request.user return user.accounts.all()
-
get_serializer_class(self)
返回序列化器类,默认返回
serializer_class
,可以重写,例如:def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer
-
get_serializer(self,_args, *_kwargs)
返回序列化器对象,被其他视图或扩展类使用,如果我们在视图中想要获取序列化器对象,可以直接调用此方法。
注意,在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
-
-
详情视图使用:
-
get_object(self)返回详情视图所需的模型类数据对象,默认使用
lookup_field
参数来过滤queryset。 在试图中可以调用该方法获取详情信息的模型类对象。若详情访问的模型类对象不存在,会返回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() serializer = self.get_serializer(book) return Response(serializer.data)
-
三、Mixin类视图
- Mixin类 定义了一些 方法,
- 通过使用 GenericAPIView 提供的方法、属性,
- 实现 列表和详情页的 快速实现
-
ListModelMixin
快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
class ListModelMixin(object): """ List a queryset. """ def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated _response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
举例:
from rest_framework.mixins import ListModelMixin from rest_framework.generics import GenericAPIView class ListModelView(ListModelMixin,GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self,request): return self.list(request) # 使用 ListModelMixin 类的 list()方法
-
CreateModelMixin
快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin(object): """ Create a model instance. """ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
举例:
from rest_framework.mixins import CreateModelMixin class ListModelView(CreateModelMixin,GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def post(self,request): return self.create(request) # 使用 CreateModelMixin 类的 create()方法
-
RetrieveModelMixin
快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
class RetrieveModelMixin(object): """ Retrieve a model instance. """ def retrieve(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data)
例如:
from rest_framework.mixins import RetrieveModelMixin class ListModelView(RetrieveModelMixin,GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self,request,pk): return self.retrieve(request) # 使用 RetrieveModelMixin 类的 retrieve()方法
-
UpdateModelMixin
快速实现更新一个存在的数据对象。
同时也提供
partial_update(request, *args, **kwargs)
方法,可以实现局部更新。成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin(object): """ Update a model instance. """ def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) self.perform_update(serializer) if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} return Response(serializer.data) def perform_update(self, serializer): serializer.save() def partial_update(self, request, *args, **kwargs): kwargs['partial'] = True return self.update(request, *args, **kwargs)
举例:
from rest_framework.mixins import UpdateModelMixin class ListModelView(UpdateModelMixin,GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def put(self,request,pk): return self.update(request)
-
DestroyModelMixin
快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class UpdateModelMixin(object): """ Update a model instance. """ def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) self.perform_update(serializer) if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} return Response(serializer.data) def perform_update(self, serializer): serializer.save() def partial_update(self, request, *args, **kwargs): kwargs['partial'] = True return self.update(request, *args, **kwargs)
举例:
from rest_framework.mixins import DestroyModelMixin class ListModelView(DestroyModelMixin,GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def delete(self,request,pk): return self.destroy(request)
四、几个可用子类视图 ,
只不过是在继承时 省略合并了(XX_ModelMixin,GenericAPIView)
1) CreateAPIView
提供 post 方法
继承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin
3)RetireveAPIView
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
4)DestroyAPIView
提供 delete 方法
继承自:GenericAPIView、DestroyModelMixin
5)UpdateAPIView
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
6)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
7)RetrieveUpdateDestroyAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin
六、视图集
6.1 ViewSet
ViewSet
类只是一种基于类的View,继承自APIView
它不提供任何方法处理程序(如
get()
orpost()
),而是提供诸如
list()
和create()
之类的操作。
优点:
- 重复的逻辑可以合并成一个类。例如我们只需要指定
queryset
一次,它将用于多个视图。 - 通过使用路由器,我们不再需要处理自己的URL配置
6.2 GenericViewSet
6.3 ModelViewSet
6.4 路由Router
DefaultRouter与SimpleRouter的区别是:
DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
1) 创建router对象,并注册视图集,注册语法为
# register(prefix, viewset,base_name) # prefix 该视图集的路由前缀 # viewset 视图集 # base_name 路由名称的前缀 from rest_framework import routers router = routers.SimpleRouter() # router = routers.DefaultRouter # (提供API根视图) router.register(r'books', BookViewSet, base_name='book')
- 添加路由数据
urlpatterns = [
...
]
urlpatterns += router.urls
# 或
urlpatterns = [
...
url(r'^', include(router.urls))
]
网友评论