博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DRF 视图和路由
阅读量:6979 次
发布时间:2019-06-27

本文共 9102 字,大约阅读时间需要 30 分钟。

Django Rest Feamework 视图和路由

DRF的视图

APIView

我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不同呢

urlpatterns = [    url(r'^book$', BookView.as_view()),    url(r'^book/(?P
\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的一些区别~~当然还有~~后面我们还会说~~

我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码~~

那么我们尝试着来进行封装一下~~

第一次封装

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("删除的书籍不存在")
APIView视图
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):    passclass RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):    passclass 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应该对应我们处理的方法~

这样我们每个视图就不用在写函数了~因为已经和内部实现的函数相对应了~

第三次封装

urlpatterns = [    # url(r'^book$', BookView.as_view()),    # url(r'^book/(?P
\d+)$', BookEditView.as_view()), url(r'^book$', BookView.as_view({
"get": "list", "post": "create"})), url(r'^book/(?P
\d+)$', BookView.as_view({
"get": "retrieve", "patch": "update", "delete": "destroy"})),]
路由urls.py
from rest_framework.viewsets import ViewSetMixin# class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):#     queryset = Book.objects.all()#     serializer_class = BookSerializer        # 如果我们再定义一个类class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):    passclass BookView(ModelViewSet):    queryset = Book.objects.all()    serializer_class = BookSerializer
第三次封装

 我们现在的视图就只要写两行就可以了~~~

其实我们写的所有的视图~框架都帮我们封装好了~

注意一点~~用框架封装的视图~我们url上的那个关键字参数要用pk~~系统默认的~~

奉献一张图来看下我们的继承顺序~~~

DRF的路由

1,自定义路由

from django.conf.urls import url, includefrom web.views import s11_renderurlpatterns = [    url(r'^test/$', s11_render.TestView.as_view()),    url(r'^test\.(?P
[a-z0-9]+)$', s11_render.TestView.as_view()), url(r'^test/(?P
[^/.]+)/$', s11_render.TestView.as_view()), url(r'^test/(?P
[^/.]+)\.(?P
[a-z0-9]+)$', s11_render.TestView.as_view())]
urls.py
from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom .. import modelsclass TestView(APIView):    def get(self, request, *args, **kwargs):        print(kwargs)        print(self.renderer_classes)        return Response('...')
views.py

2,半自动路由

from django.conf.urls import url, includefrom web.views import s10_genericurlpatterns = [    url(r'^test/$', s10_generic.UserViewSet.as_view({
'get': 'list', 'post': 'create'})), url(r'^test/(?P
\d+)/$', s10_generic.UserViewSet.as_view( {
'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),]
urls.py
from rest_framework.viewsets import ModelViewSetfrom rest_framework import serializersfrom .. import modelsclass UserSerializer(serializers.ModelSerializer):    class Meta:        model = models.UserInfo        fields = "__all__"class UserViewSet(ModelViewSet):    queryset = models.UserInfo.objects.all()    serializer_class = UserSerializer
views.py

3,全自动路由

from django.conf.urls import url, includefrom rest_framework import routersfrom web.views import s10_genericrouter = routers.DefaultRouter()router.register(r'users', s10_generic.UserViewSet)urlpatterns = [    url(r'^', include(router.urls)),]
urls.py
from rest_framework.viewsets import ModelViewSetfrom rest_framework import serializersfrom .. import modelsclass UserSerializer(serializers.ModelSerializer):    class Meta:        model = models.UserInfo        fields = "__all__"class UserViewSet(ModelViewSet):    queryset = models.UserInfo.objects.all()    serializer_class = UserSerializer
views.py

 

转载于:https://www.cnblogs.com/peng104/p/10140828.html

你可能感兴趣的文章
用python itchat写一个微信机器人自动回复
查看>>
MAC 微信表情包 导出
查看>>
spring cloud gateway的stripPrefix配置
查看>>
JavaScript对象深拷贝/浅拷贝遇到的坑和解决方法
查看>>
GitHub 从单机到联机:玩转 Pull Request
查看>>
ES2018 新特征之:非转义序列的模板字符串
查看>>
Python反序列化安全问题
查看>>
ArrayList实现原理
查看>>
再也不用担心网页编码的坑了!
查看>>
leetcode225 basic calculator
查看>>
Redis 内存分配分析
查看>>
spring mvc如何计算BEST_MATCHING_PATTERN_ATTRIBUTE
查看>>
关于地址栏url的一些小结
查看>>
Flutter中的布局绘制流程简析(一)
查看>>
CodeIgniter在nginx下的配置
查看>>
jQuery源码 - extend 继承&拷贝 解析
查看>>
Annotation注解(一)- 基础
查看>>
ionic工作原理
查看>>
【ios】textField 运行状态以及两种关闭键盘的方式
查看>>
leetcode 345. Reverse Vowels of a String
查看>>