Django Rest Framework 视图和路由
Django Rest Framework 视图和路由
DRF的视图
APIView
我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不同呢~~~
urlpatterns = [
url(r'^book$', BookView.as_view()),
url(r'^book/(?P<id>\d+)$', BookEditView.as_view()),
]
我们可以看到,不管是View还是APIView最开始调用的都是as_view()方法~~那我们走进源码看看~~

我们能看到,APIView继承了View, 并且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。
那我们看看View中的as_view()方法做了什么~

我们看到了~在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法~~但是这里的dispatch方法应该是我们APIView中的~~

我们去initialize_request中看下把什么赋值给了request,并且赋值给了self.request, 也就是我们在视图中用的request.xxx到底是什么~~

我们看到,这个方法返回的是Request这个类的实例对象~~我们注意我们看下这个Request类中的第一个参数request,是我们走我们django的时候的原来的request~

我们看到了,这个Request类把原来的request赋值给了self._request, 也就是说以后_request是我们老的request,新的request是我们这个Request类~~
那我们继承APIView之后请求来的数据都在哪呢~~

我们用了rest_framework框架以后,我们的request是重新封装的Request类~
request.query_params 存放的是我们get请求的参数
request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求~~~
相比原来的django的request,我们现在的request更加精简,清晰了~~~
现在我们知道了APIView和View的一些区别~~当然还有~~后面我们还会说~~
我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码~~
那么我们尝试着来进行封装一下~~
第一次封装
APIView视图
class BookView(APIView):
def get(self, request):
query_set = Book.objects.all()
book_ser = BookSerializer(query_set, many=True)
return Response(book_ser.data)
def post(self, request):
query_set = request.data
book_ser = BookSerializer(data=query_set)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors)
class BookEditView(APIView):
def get(self, request, id):
query_set = Book.objects.filter(id=id).first()
book_ser = BookSerializer(query_set)
return Response(book_ser.data)
def patch(self, request, id):
query_set = Book.objects.filter(id=id).first()
book_ser = BookSerializer(query_set, data=request.data, partial=True)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors)
def delete(self, request, id):
query_set = Book.objects.filter(id=id).first()
if query_set:
query_set.delete()
return Response("")
else:
return Response("删除的书籍不存在")
第一次封装
class GenericAPIView(APIView):
queryset = None
serializer_class = None def get_queryset(self):
return self.queryset.all() def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs) class ListModelMixin(object):
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data) class CreateModelMixin(object):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.validated_data)
else:
return Response(serializer.errors) class RetrieveModelMixin(object):
def retrieve(self, request, id, *args, **kwargs):
book_obj = self.get_queryset().filter(pk=id).first()
book_ser = self.get_serializer(book_obj)
return Response(book_ser.data) class UpdateModelMixin(object):
def update(self, request, id, *args, **kwargs):
book_obj = self.get_queryset().filter(pk=id).first()
book_ser = self.get_serializer(book_obj, data=request.data, partial=True)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors) class DestroyModelMixin(object):
def destroy(self, request, id, *args, **kwargs):
queryset = self.get_queryset()
try:
queryset.get(pk=id).delete()
return Response("")
except Exception as e:
return Response("信息有误")
# 我们把公共的部分抽出来 这样不管写多少表的增删改查都变的很简单
# 这样封装后我们的视图会变成这样 class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer 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 BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request, id, *args, **kwargs):
return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs):
return self.update(request, id, *args, **kwargs) def destroy(self, request, id, *args, **kwargs):
return self.delete(request, id, *args, **kwargs) 第一次封装
我们封装的GenericAPIView,包括封装每个方法的类,其实框架都帮我们封装好了~~
我们可以直接继承这些类~~来实现上面的视图~~可是还有没有更简单的方法呢~我们再次封装一下~~
第二次封装
# 上面我们写的继承类太长了~~我们再改改 class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
pass class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer 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 BookEditView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request, id, *args, **kwargs):
return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs):
return self.update(request, id, *args, **kwargs) def delete(self, request, id, *args, **kwargs):
return self.delete(request, id, *args, **kwargs) 第二次封装
这次我们只是让继承变的简单了一点而已,好像并没有什么大的进步~~
我们可不可以把这两个视图合并成一个视图呢~~~框架给我们提供了一个路由传参的方法~~
我们看下ViewSetMixin

actions这个默认参数其实就是我们路由可以进行传参了~~~
下面这个循环~可以看出~我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法~
这样我们每个视图就不用在写函数了~因为已经和内部实现的函数相对应了~
第三次封装
路由urls.py
urlpatterns = [
# url(r'^book$', BookView.as_view()),
# url(r'^book/(?P<id>\d+)$', BookEditView.as_view()),
url(r'^book$', BookView.as_view({"get": "list", "post": "create"})),
url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
]
第三次封装
from rest_framework.viewsets import ViewSetMixin # class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
# queryset = Book.objects.all()
# serializer_class = BookSerializer # 如果我们再定义一个类
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
pass class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
我们现在的视图就只要写两行就可以了~~~
其实我们写的所有的视图~框架都帮我们封装好了~
注意一点~~用框架封装的视图~我们url上的那个关键字参数要用pk~~系统默认的~~
奉献一张图来看下我们的继承顺序~~~


DRF的路由
我们上面的路由传参写的特别多~~框架也帮我们封装好了~
路由
from .views import BookView
from rest_framework.routers import DefaultRouter router = DefaultRouter()
router.register(r"book", BookView) urlpatterns = [
# url(r'^book$', BookView.as_view()),
# url(r'^book/(?P<id>\d+)$', BookEditView.as_view()),
# url(r'^book$', BookView.as_view({"get": "list", "post": "create"})),
# url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})), ]
urlpatterns += router.urls
我们可以看到~~通过框架我们可以把路由视图都变的非常简单~~
但是需要自定制的时候还是需要我们自己用APIView写~~当不需要那么多路由的时候~也不要用这种路由注册~~
总之~~一切按照业务需要去用~~~
Django Rest Framework 视图和路由的更多相关文章
- 03 Django REST Framework 视图和路由
01-DRF中的request 在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等. 比如,区别 ...
- python 全栈开发,Day96(Django REST framework 视图,django logging配置,django-debug-toolbar使用指南)
昨日内容回顾 1. Serializer(序列化) 1. ORM对应的query_set和ORM对象转换成JSON格式的数据 1. 在序列化类中定义自定义的字段:SerializerMethodFie ...
- [Django REST framework - 视图组件之视图基类、视图扩展类、视图子类、视图集]
[Django REST framework - 视图组件之视图基类.视图扩展类.视图子类.视图集] 视图继承关系 详图见文章末尾 视图组件可点我查看 两个视图基类:APIView.GenericAP ...
- Django REST framework - 视图
目录 Django REST framework 视图GenericAPIView GenericAPIView 例子 属性 混入 具体视图类 自定义基类 Django REST framework ...
- Django的View(视图)和路由系统
一.Django的View(视图) 1.介绍 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一 ...
- Django REST framework视图
混合类阶段(封装2次) 路由: url(r'school/$', views.SchoolView.as_view()), url(r'school/(?P<pk>\d+)/$', vie ...
- rest framework 视图,路由
视图 在上面序列化的组件种已经用到了视图组件,即在视图函数部分进行逻辑操作. 但是很明显的弊端是,对每个表的增删改查加上 单条数据,需要用到 2个类 5个方法(增删改查,单数据查)才可以完整的实现,当 ...
- DRF (Django REST framework) 中的路由Routers
路由Routers 注意是:对于视图集ViewSet!!!我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息. REST frame ...
- DRF 视图组件,路由组件
视图组件 -- 第一次封装 -- GenericAPIView(APIView): queryset = None serializer_class = None def ge ...
随机推荐
- nginx1.14.0下载、安装、启动
nginx1.14.0下载及安装 wget http://nginx.org/download/nginx-1.14.0.tar.gztar -zxvf nginx-1.14.0.tar.gzcd n ...
- 使用uiautomator2进行webview页面的测试
1.开发开启webview debug模式 2.使用VirtualXposed框架进行webview测试,详细见https://testerhome.com/topics/16156 下载,安装Vir ...
- 基于STM8的GPIO操作---STM8-第一章
1. 综诉 也许单片机在你看来是一件不太容易的事,但据我所知,单片机,无非就是控制它的GPIO口,所以可以看出,学会如何操作控制GPIO口对使用单片机来说是很重要的一件事. 在装载STM8的单片机中, ...
- 关于__cmp__的使用
__cmp__是python的类中所使用的特殊函数,一般用于对类对象列表的排序. 举个例子,假设需要对Student类的对象列表按照其成绩grade属性进行排序,那么可以这么设计: class Stu ...
- Django models中的null和blank的区别
blank在数据库上存储的是一个空字符串 如需设置字段可以为空:blank=True,默认为blank=False(字段必须填写); null在数据库上表现为NULL,而不是一个空字符串 如需设置字段 ...
- PHP大神必须养成的十大优良习惯
1.多阅读手册和源代码 没什么比阅读手册更值得强调的事了–仅仅通过阅读手册你就可以学习到很多东西,特别是很多有关于字符串和数组的函数.就在这些函数里面包括许多有用 的功能,如果你仔细阅读手册,你会经常 ...
- MySQL(进阶部分)
视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用. SELECT * FROM ( SEL ...
- 为什么移动构造要使用noexcept
vector::push_back操作,保证了如果过程中出现异常,vector不会发生变化. push_back过程中,可能会因为已有内存空间不够,申请新的内存,同时把原内存中已有的元素,放到新申请的 ...
- JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案
一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密码. 2.服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色.登录时间等等. ...
- 解决PLSQL Developer 插入中文 乱码问题
https://blog.csdn.net/guowd/article/details/50989109 PLSQL Developer 插入中文 乱码问题,如图 这个是由于oracle服务器端字符编 ...