rest-framework框架——视图三部曲
一、mixins类编写视图
1、配置url
urlpatterns = [
...
re_path(r'^authors/$', views.AuthorView.as_view(), name="author"),
re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(), name="detail_author")
]
2、编写Author的序列化类
/app01/serializer.py:
class AuthorModelSerializers(serializers.ModelSerializer):
class Meta:
model = Author
fields = "__all__"
3、编写Author的视图
# Author
from rest_framework import mixins, generics class AuthorView(mixins.ListModelMixin, # 扩展了列出查询集功能
mixins.CreateModelMixin, # 扩展了创建和保存新模型实例功能
generics.GenericAPIView): # 继承扩展了REST框架的APIView类,为标准列表和详细视图添加了常见的行为
queryset = Author.objects.all() # 配置queryset:告知这个类这次处理的数据
serializer_class = AuthorModelSerializers # 告知处理用到的序列化组件 def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs) class AuthorDetailView(mixins.RetrieveModelMixin, # 扩展在响应中实现返回现有模型实例功能(获取单条数据)
mixins.DestroyModelMixin, # 扩展现有模型实例的删除功能
mixins.UpdateModelMixin, # 扩展更新和保存现有模型实例功能
generics.GenericAPIView):
queryset = Author.objects.all() # 配置queryset:告知这个类这次处理的数据
serializer_class = AuthorModelSerializers # 告知处理用到的序列化组件 def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
注意:
(1)queryset和serializer_class变量
这两个变量是必须的。queryset告知这个类这次处理的数据。serializer_class告知这个类数据处理用到的序列化组件。
(2)五类mixins作用和对应的http方法
(3)GenericAPIView
这个类扩展了REST框架的APIView
类,为标准列表和详细视图添加了常见的行为。
提供的每个具体的通用视图都是通过把GenericAPIView
与一个或多个mixin类进行组合来构建的。
(4)测试验证
二、基于mixins封装视图示例
1、基本视图
# 方式三:基于rest_framework框架实现序列化(pip install djangorestframework)
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer # 自定义序列化类 class BookView(APIView):
query_set = Book.objects.all() # 将query_set抽离
serializer_class = BookSerializer # 拿到序列化器 def get(self, request):
# 第一个图书对象
# book_obj = Book.objects.first()
# ret = BookSerializer(book_obj) # book_list = Book.objects.all()
book_list = self.query_set
# ret = BookSerializer(book_list, many=True) # 使用序列化器序列化
ret = self.serializer_class(book_list, many=True)
"""
序列化的数据保存在ret.data中
"""
return Response(ret.data)
"""
得出来的结果会使用Django REST framework模板,在serializers.py中定制好序列化类后,显示效果如下所示:
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept [
{
"id": 1,
"title": "python开发",
"category": "Python",
"pub_time": "2011-08-27",
"publisher": {
"id": 1,
"title": "人民日报社"
},
"author": [
{
"id": 1,
"name": "xxx"
},
{
"id": 2,
"name": "sssxx"
}
]
},
...
]
""" def post(self, request):
print(request.data)
serializer = BookSerializer(data=request.data) # 序列化器校验前端传回来的数据
if serializer.is_valid():
serializer.save() # 验证成功后保存数据库
# 因为ModelSerializer的create方法不支持source的用法。因此必须还自定义一个create方法。
return Response(serializer.validated_data) # validated_data存放验证通过的数据
else:
return Response(serializer.errors) # errors存放错误信息 '''
发送post请求接口设计
POST /books/list
{
"title": "nodejs的使用教程",
"w_category": "1",
"pub_time": "2018-10-27",
"publisher_id": 1,
"author_list": [1,2,3]
}
''' class BookEditView(APIView):
def get(self, request, id):
"""查看单条数据"""
book_obj = Book.objects.filter(id=id).first()
ret = BookSerializer(book_obj)
return Response(ret.data) '''
GET /books/retrieve/3
{
"id": 3,
"title": "Linux开发",
"category": "Linux",
"pub_time": "2008-08-27",
"publisher": {
"id": 3,
"title": "长江日报社"
},
"author": [
{
"id": 1,
"name": "阿萨德"
},
{
"id": 3,
"name": "阿斯达"
}
]
}
''' def put(self, request, id):
"""更新操作"""
book_obj = Book.objects.filter(id=id).first()
serializer = BookSerializer(
book_obj, # 待更新对象
data=request.data, # 要更新的数据
partial=True # 重点:进行部分验证和更新
)
if serializer.is_valid():
serializer.save() # 保存
return Response(serializer.validated_data) # 返回验证通过的数据
# return Response(serializers.data) # 返回所有数据
else:
return Response(serializer.errors) # 返回验证错误的数据 def delete(self, request, id):
"""删除操作"""
book_obj = Book.objects.filter(id=id).first()
book_obj.delete()
return Response("")
2、基于mixins封装视图
升级:改写使用通用类,继承通用方法。
class GenericAPIView(APIView):
# 通用APIView模板类
query_set = None
serializer_class = None def get_queryset(self):
return self.query_set def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs) # 实例化,且接收所有的参数 class BookView(GenericAPIView):
# 以方法的形式调用获取
query_set = Book.objects.all()
serializer_class = BookSerializer def get(self, request):
book_list = self.get_queryset()
ret = self.get_serializer(book_list, many=True)
return Response(ret.data) def post(self, request):
serializer = BookSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
3、第一次封装
class GenericAPIView(APIView):
# 通用APIView模板类
query_set = None
serializer_class = None def get_queryset(self):
return self.query_set def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs) # 实例化,且接收所有的参数 class ListModelMixin(object):
def list(self, request):
queryset = self.get_queryset()
ret = self.get_serializer(queryset, many=True)
return Response(ret.data) class CreateModelMixin(object):
def create(self, request):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors) class RetrieveModelMixin(object):
def retrieve(self, request, id): # 查看单条数据
book_obj = self.get_queryset().filter(id=id).first()
ret = self.get_serializer(book_obj)
return Response(ret.data) class UpdateModelMixin(object):
def update(self, request, id):
book_obj = self.get_queryset().filter(id=id).first()
serializer = self.get_serializer(
book_obj, # 待更新对象
data=request.data, # 要更新的数据
partial=True # 重点:进行部分验证和更新
)
if serializer.is_valid():
serializer.save() # 保存
return Response(serializer.validated_data) # 返回验证通过的数据
# return Response(serializers.data) # 返回所有数据
else:
return Response(serializer.errors) # 返回验证错误的数据 class DestroyModelMixin(object):
def delete(self, request, id):
book_obj = self.get_queryset().filter(id=id).first()
book_obj.delete()
return Response("") class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): # 一层封装
query_set = Book.objects.all()
serializer_class = BookSerializer def get(self, request):
return self.list(request) def post(self, request):
return self.create(request) class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): # 一层封装
query_set = Book.objects.all()
serializer_class = BookSerializer def get(self, request, id):
"""查看单条数据"""
return self.retrieve(request, id) def put(self, request, id):
"""更新操作"""
return self.update(request, id) def delete(self, request, id):
"""删除操作"""
return self.destroy(request, id)
4、第二次封装
进一步封装如下所示:
# 二层封装
class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
pass # class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): # 一层封装
class BookView(ListCreateAPIView): # 使用二层封装
query_set = Book.objects.all()
serializer_class = BookSerializer def get(self, request):
return self.list(request) def post(self, request):
return self.create(request) # class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): # 一层封装
class BookEditView(RetrieveUpdateDestroyAPIView): # 使用二层封装
query_set = Book.objects.all()
serializer_class = BookSerializer def get(self, request, id):
"""查看单条数据"""
return self.retrieve(request, id)
5、第三次封装
经过两次封装后,剩下两个视图,但依然不够简洁。由于两个get请求的返回值不同,写了两个视图来解决。
现在可以通过路由传参的方式来解决上述问题。
(1)改写urls.py
from django.urls import path, include
from .views import BookView, BookEditView, BookModelViewSet urlpatterns = [
# path('list', BookView.as_view()), # 查看所有的图书
# 注意url中参数命名方式,2.0之前的写法:'retrieve/(?P<id>\d+)'
# 2.0之后的写法:<>内声明类型,冒号后面跟着关键字参数
# path('retrieve/<int:id>', BookEditView.as_view()) # 单条数据查看 path('list', BookModelViewSet.as_view({"get": "list", "post": "create"})),
path('retrieve/<int:id>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}))
]
(2)使as_view支持传参
as_view方法本身是不支持传参的,因此需要重写该方法。
class ViewSetMixin(object):
def as_view(self):
"""
按照参数指定的去匹配
get-->list
:return:
"""
pass class BookModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin,
RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
pass
但是我们不用自己去定义该方法,可以直接使用框架已经提供好的ViewSetMixin:
from rest_framework.viewsets import ViewSetMixin
它做的主要事情就是重写as_view方法:
class ViewSetMixin:
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# We also store the mapping of request methods to actions,
# so that we can later set the action attribute.
# eg. `self.action = 'list'` on an incoming GET request.
self.action_map = actions # Bind methods to actions
# This is the bit that's different to a standard view
# 这里actions是前面url中提供的字典参数{"get": "list", "post": "create"}
for method, action in actions.items():
# 循环得到的method是get,action是list
handler = getattr(self, action) # self是自己的视图类
setattr(self, method, handler) # 在自己的视图类中找list方法 if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get self.request = request
self.args = args
self.kwargs = kwargs # And continue as usual
# 做分发:get-->self.get;post-->self.post
return self.dispatch(request, *args, **kwargs)
由于self.get已经等于self.list,分发get对应的是list。
(3)视图改写
from rest_framework.viewsets import ViewSetMixin class BookModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin,
RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
query_set = Book.objects.all()
serializer_class = BookSerializer
由于get去匹配时已经自动对应到了self.list方法。因此不再自定义视图方法。
(4)简化继承
from rest_framework.viewsets import ViewSetMixin class ModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
pass class BookModelViewSet(ModelViewSet):
query_set = Book.objects.all()
serializer_class = BookSerializer
三、Mixins源码分析
1、CreateModelMixin
class CreateModelMixin(object):
"""Create a model instance ==>创建一个实例"""
def create(self, request, *args, **kwargs):
# 获取相关serializer
serializer = self.get_serializer(data=request.data) # 进行serializer的验证;raise_exception=True,一旦验证不通过,不再往下执行,直接引发异常
serializer.is_valid(raise_exception=True) # 调用perform_create()方法,保存实例
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 {}
注意:
(1)perform_create( )对serializer直接进行save保存,当在一些情境下,需要对perform_create( )进行重写。
(2)这个类的运行流程如下所示:
2、ListModelMixin
class ListModelMixin(object):
"""List a queryset.==> 列表页获取"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset()) # 这是一个分页功能,如果在viewset中设置了pagination_class,那么这里就会起作用
# 获取当前页的queryset,如果不存在分页,返回None
page = self.paginate_queryset(queryset) if page is not None:
# 分页不为空,那么不能简单的执行Response(serializer.data)
# 还需要将相关的page信息序列化在进行响应
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)
ListModelMixin一般用来获取列表页,不需要重写方法。
3、RetriveModelMixin
class RetrieveModelMixin(object):
"""
Retrieve a model instance.==> 获取某一个对象的具体信息
"""
def retrieve(self, request, *args, **kwargs):
# 一般访问的url都为/obj/id/这种新式
# get_object()可以获取到这个id的对象
# 注意在viewset中设置lookup_field获取重写get_object()方法可以指定id具体对象是什么~!
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
4、DestoryModelMixin
class DestroyModelMixin(object):
"""
Destroy a model instance.
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance):
instance.delete()
5、总结
这一章简要分析了源码的内容以及各个mixins的逻辑,最重要的还是学会重写它们相关的方法。一般情况下,当我们在操作某一个model的时候,涉及到另外一个model中数据的修改,那么就需要对这个mixins下执行save的逻辑的方法进行重写。
四、使用通用的基于类的视图
通过使用mixin类,使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py
模块。
from rest_framework import mixins, generics class AuthorView(generics.ListCreateAPIView):
queryset = Author.objects.all() # 配置queryset:告知这个类这次处理的数据
serializer_class = AuthorModelSerializers # 告知处理用到的序列化组件 class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Author.objects.all() # 配置queryset:告知这个类这次处理的数据
serializer_class = AuthorModelSerializers # 告知处理用到的序列化组件
1、ListCreateAPIView源码
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset or creating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
可以看到源码中将Mixins混合类和get\post函数都封装进去了。
2、RetrieveUpdateDestroyAPIView源码
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for retrieving, updating or deleting a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs) def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs) def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
其他RetrieveDestroyAPIView、RetrieveUpdateAPIView、UpdateAPIView、DestroyAPIView等封装方式完全类似。
五、运用viewsets.ModelViewSet的视图
1、改写urls.py
from django.contrib import admin
from django.urls import path, re_path
from app01 import views urlpatterns = [
path('admin/', admin.site.urls),
'''代码省略'''
# re_path(r'^authors/$', views.AuthorView.as_view(), name="author"),
# re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(), name="detail_author"), # as_view参数指定什么请求走什么方法
re_path(r'^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author_list"),
re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="author_detail"),
]
注意:
(1)as_view参数
利用参数来指定什么请求方式由哪一个内部方法来执行。尤其注意两种不同get请求用不同的方法来处理。
2、引入viewsets改写视图
from rest_framework import viewsets class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all() # 配置queryset:告知这个类这次处理的数据
serializer_class = AuthorModelSerializers # 告知处理用到的序列化组件
五、ModelViewSet源码分析
1、查看viewsets.ModelViewSet源码
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
ModelViewSet继承了所有五个混合类。还继承了GenericViewSet类。
2、查看GenericViewSet源码
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
可以看到GenericViewSet继承了前面学的generics.GenericAPIView类,这个类扩展了REST框架的APIView
类,但是它并没有改写dispatch方法,因此url中可以添加参数与它无关。
GenericViewSet还继承了ViewSetMixin类。
3、查看分析ViewSetMixin源码
class ViewSetMixin(object):
"""
Overrides `.as_view()` so that it takes an `actions` keyword that performs
the binding of HTTP methods to actions on the Resource.
覆盖as_view方法需要接收一个actions参数来实现将HTTP方法绑定到资源。
For example, to create a concrete view binding the 'GET' and 'POST' methods
to the 'list' and 'create' actions...
举例来说,如果要创建一个具体视图绑定'GET'和'POST'方法到'list'和'create'操作。可写为如下格式:
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
"""
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
"""
Because of the way class based views create a closure around the
instantiated view, we need to totally reimplement `.as_view`,
and slightly modify the view function that is created and returned.
"""
# actions must not be empty actions来接收{'get': 'list', 'post': 'create'}
if not actions: # 为空则报错
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`") # sanitize keyword arguments
for key in initkwargs:..... # 这里的值是空的 def view(request, *args, **kwargs):... return csrf_exempt(view) # 执行as_view 最终返回的还是view函数
注意:
(1)分析函数传参方式:**字典传参等同于关键字传参。
def foo(action=None, **kwargs):
print(action)
print(kwargs) foo({"a": 1}, b=2, c=3)
"""
{'a': 1}
{'b': 2, 'c': 3}
"""
foo(a=2, b=3)
"""
None
{'a': 2, 'b': 3}
"""
foo(**{"a": 1, "b": 3})
"""
None
{'a': 1, 'b': 3}
"""
foo({"a": 1, "b": 3})
"""
{'a': 1, 'b': 3}
{}
"""
由此可见as_view传递的参数{"get": "list", "post": "create"}是ViewSetMixin内改写的as_view方法,由actions参数来接收的。
由于acitons默认值是None,因此not None其实是True,if not actions: 其实是actions为空则报错的意思。
(2)as_view函数最终返回值是view函数
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# We also store the mapping of request methods to actions,
# so that we can later set the action attribute.
# eg. `self.action = 'list'` on an incoming GET request.
self.action_map = actions # 传入的字典数据{'get': 'list', 'post': 'create'} # Bind methods to actions
# This is the bit that's different to a standard view
for method, action in actions.items(): # method:请求方式 action:实例方法
handler = getattr(self, action) # 反射得到self.list self.create方法
setattr(self, method, handler) # 给请求方式设置对应的实例方法 if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get self.request = request
self.args = args
self.kwargs = kwargs # And continue as usual
return self.dispatch(request, *args, **kwargs)
在view函数中用self.action_map = actions 来接收传入的字典数据{'get': 'list', 'post': 'create'}。
循环for method, action in actions.items(): 拿到method:请求方式和action:实例方法。
再通过反射方法:handler = getattr(self, action) 得到self.list self.create方法。
最后通过反射方法setattr(self, method, handler) 给请求方式设置对应的实例方法:以后再找getattr(self, "get")的时候找到是self.list;找getattr(self, "post")的时候找到是self.create;
(3)反射方法详解
1. getattr()函数是Python自省的核心函数,具体使用大体如下:
class A:
def __init__(self):
self.name = 'zhangjing'
#self.age='24'
def method(self):
print"method print" Instance = A()
print getattr(Instance , 'name, 'not find') #如果Instance 对象中有属性name则打印self.name的值,否则打印'not find'
print getattr(Instance , 'age', 'not find') #如果Instance 对象中有属性age则打印self.age的值,否则打印'not find'
print getattr(a, 'method', 'default') #如果有方法method,否则打印其地址,否则打印default
print getattr(a, 'method', 'default')() #如果有方法method,运行函数并打印None否则打印default 2. hasattr(object, name) 说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的) 3. setattr(object, name, value) 这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串可能会列出一个现有的属性或一个新的属性。这个函数将值赋给属性的。该对象允许它提供。例如,setattr(x,“foobar”,123)相当于x.foobar = 123。 4. delattr(object, name) 与setattr()相关的一组函数。参数是由一个对象(记住python中一切皆是对象)和一个字符串组成的。string参数必须是对象属性名之一。该函数删除该obj的一个由string指定的属性。delattr(x, 'foobar')=del x.foobar
4、找到view函数执行完后最终返回dispatch方法 并完成分析
从ModelViewSet——》GenericViewSet——》GenericAPIView——》APIView一路回溯到APIView才找到dispatch方法。
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate? try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
当访问是走的路由是re_path(r'^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author_list"),get请求handler对应的是self.list。
而当访问走的路由是re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view({'get': 'retrieve',....
此时get请求handler对应的是self.retrieve。
如此就实现了两个类合成一个类。
5、找到并执行list方法
查看ModelViewSet源码:
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
在ListModelMixin找到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)
六、视图组件总结
1、DRF所有视图文件
所有的视图类在如下这四个文件内:
from rest_framework import views # APIView
from rest_framework import generics # 公共通用视图类:GenericAPIView,及各种组合视图类CreateAPIView、ListAPIView、RetrieveAPIView等
from rest_framework import mixins # 混合继承类:CreateModelMixin、ListModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin
from rest_framework import viewsets # 重写as_view: ViewSetMixin;其他类都是帮助去继承ViewSetMixin
2、DRF视图图谱
视图类继承顺序,如Django REST Framework视图图谱所示:
首先 django是继承 view的,DRF是从APIView开始继承起,APIView封装了request,其中包含了data、query_params等属性、方法。
然后 GenericAPIView封装了 get_queryset() 和 get_serializer();ViewSetMixin重写了 as_view()方法。
随后 GenericViewSet帮忙继承GenericAPIView和ViewSetMixin。
最后最高层的封装是 ModelViewSet。
rest-framework框架——视图三部曲的更多相关文章
- django的rest framework框架——分页、视图、路由、渲染器
一.rest framework的分页 1.使用rest framework内置类PageNumberPagination实现分类 from django.conf.urls import url f ...
- Git.Framework 框架随手记--存储过程简化
在很多的ORM中对存储过程操作都是一个棘手的地方,因为存储过程是一段预编译的代码,其中可以包含很多处理过程.在Git.Framework中也同样存在这样的问题,目前没有能力解决这个问题.但是对于存储过 ...
- Django_rest framework 框架介绍
restful介绍 restful协议 一切皆是资源,操作只是请求方式 URL 设计 原先的URL设计方式 在url 中体现出操作行为 /books/ books /books/add/ addbo ...
- Django REST framework框架介绍和基本使用
Django REST framework介绍 Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API. 官 ...
- Django Rest framework 框架之认证使用和源码执行流程
用这个框架需要先安装: pip3 install djangorestframework 如果写了一个CBV的东西,继承了View. # 继承Django里面View class APIView(Vi ...
- Django Rest framework 框架
一.开发模式: 1. 普通开发方式(前后端放在一起写) 2. 前后端分离(前后台通过ajaxo交互) 后端(django rest framework写的) <----ajaxo---> ...
- Django之Rest Framework框架
一.什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角度 ...
- Django----Rest Framework框架
Django Rest Framework框架(10) - RESTful规范 1.API与用户的通信协议,总是使用HTTPs协议. 2.域名 https://api.example.com 尽量将A ...
- rest-framework组件 之 视图三部曲
浏览目录 使用混合(mixins) mixin类编写视图 使用通用的基于类的视图 viewsets.ModelViewSet 视图三部曲 使用混合(mixins) from rest_framewor ...
随机推荐
- js appendChild与insertBefore 区别和用法
1.appendChild() 方法:可以向节点的子节点列表的末尾添加新的子节点. 比如:appendChild(newchild)括号里可以是创建的标签var newchild = docume ...
- Cboard Cube 实现Top X效果
第一步,点击度量值指标的排序. 第二步,点击[过滤]图标,选择Filter 在窗口中输入需要Top X的数字即可. 预览效果如下: 版权声明:本文为博主原创文章,需要转载请注明出处. [置顶]Cboa ...
- Python web前端 03 CSS属性
Python web前端 03 CSS属性 一.文字.文本属性 1.文字属性 font-family #字体类型浏览器默认的字体是微软雅黑,字体中有多个字体的时候,如果前面的字体没有就使用后面的字体 ...
- C++_代码重用4-多重继承
继承使用时要注意,默认是私有派生.所以要公有派生时必须记得加关键字Public. MI(Multi Inheritance)会带来哪些问题?以及如何解决它们? 两个主要问题: 从两个不同的基类继承同名 ...
- abp学习资料
参考: https://www.jianshu.com/p/a6e9ace79345
- SpringBoot 精简笔记
0. Fundamental a. @SpringBootApplication //启动类 b. pom.xml //Maven基本依赖 <parent> <groupId> ...
- 用jenkins编译WPF程序并传输到服务器
环境准备: 1.ide visual studio2017 Enterprise,Ide可以https://visualstudio.microsoft.com/zh-hans/downloads ...
- 把数据库内容显示在listview上
数据库操作很简单,但用户想看见的是数据库里的内容,那么让数据库内容显示在屏幕上呢,下面做个简单演示,百变不离其中,先看步骤: 把数据库的数据显示至屏幕1. 任意插入一些数据 定义Javabean:Pe ...
- 修改Android解锁界面
解锁界面效果类似如下 其实这也是我后面做出的效果,样机因为没有ROOT不好调试截图,功能是将解锁的图标添加了最近运行的运用的图标,这样的话更方便用户去使用 1.分析 1.1.Android锁屏功能分析 ...
- Android多语言与国际化
internationalization (国际化)简称 i18n,因为在i和n之间还有18个字符,localization(本地化 ),简称L10n.一般用 语言_地区的形式表示一种语言,如 zh_ ...