视图和路由

  1. 视图封装

  • 第一次封装

​ 上一篇最后我们对书籍表做了增删改查,那么如果现在我们有几十上百张表需要这样做呢?我们知道类的特性有封装,因此我们可以尝试进行封装下.

from rest_framework.views import APIView
from rest_framework.response import Response from .models import Book
from .modelSerializers import BookModelSerializer 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):
# 这个就是把get方法抽离了出来,变成了list方法
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer_data = self.get_serializer(queryset, many=True)
return Response(serializer_data.data) class CreateModelMixin(object):
def create(self, request, *args, **kwargs):
ser_obj = self.get_serializer(data=request.data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data)
return Response(ser_obj.errors) class RetrieveModelMixin(object):
def retrieve(self, request, id, *args, **kwargs):
book_obj = self.get_queryset().filter(pk=id).first()
ser_obj = self.get_serializer(book_obj)
return Response(ser_obj.data) class UpdateModelMixin(object):
def update(self, request, id, *args, **kwargs):
book_obj = self.get_queryset().filter(pk=id).first()
ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data)
return Response(ser_obj.errors) class DestroyModeMixin(object):
def destroy(self, request, id , *args, **kwargs):
book_obj = self.get_queryset().filter(id=id).first()
if not book_obj:
return Response("要删除的对象不存在")
book_obj.delete()
return Response("") class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModeMixin):
pass class BookView(ListCreateAPIView):
"""书籍相关视图"""
queryset = Book.objects
serializer_class = BookModelSerializer 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
serializer_class = BookModelSerializer def get(self, request, id, *args, **kwargs):
return self.retrieve(request, id, *args, **kwargs) def put(self, request, id, *args, **kwargs):
return self.update(request, id, *args, **kwargs) def delete(self, request, id, *args, **kwargs):
return self.destroy(request, id, *args, **kwargs)

​ 从上面我们可以知道,我们发现视图中就只有query和ModelSerializer每个方法不一样,因此,我们先定义了一个GenericAPIView,该方法就是专门获取query和ModelSerializer.再接着就是将get全部/get单条/post/put/delete方法分别再次封装到不同类中的方法中,这样在写多个表时只需要调用方法即可,但是此时你会发现继承的类有点长,因此又封装了两个类专门继承多个类,这样我们再写就只需要继承一个类了,你看这样是不是变得更简单了,我们必须学习这种封装的思想,使得自己代码更加简洁,复用性更高.

  • 二次最终封装

    上面封装似乎已经很好了,但是人总是贪婪的,上面是不是定义了两个视图针对不同操作(BookView和BookEditView),那我们想能不能只定义一个视图就完成呢?此时我们去看一下rest_framework提供的源码

    在这里先被备注下rest_framework给我们的几个视图相关的类

    from rest_framework import views        # 里面主要是有APIView
    from rest_framework import viewsets # ModelViewSet封装,继承mixins下的各个类
    from rest_framework import generics # GenericAPIView,CreateAPIView等封装
    from rest_framework import mixins # list,create,update等方法具体实现

    因为我们需要合并视图,所以我们需要在as_view()时出入对应关系的参数,所以我们看下viewsets下的ViewSetMixin类, from rest_framework.viewsets import ViewSetMixin.

    从ViewSetMixin中我们可以知道,重写了as_view()方法,并且将参数传给了action,这里我只拿出了一些需要的代码进行说明下.

    def as_view(cls, actions=None, **initkwargs):
    # actions = {"get": "list", "post": "create"}
    def view(request, *args, **kwargs):
    for method, action in actions.items():
    # method = get, action = list
    handler = getattr(self, action)
    # 这里就将self.get = self.list,所以之后get请求就会去找list方法
    setattr(self, method, handler)
    所以注意下,只有继承了ViewSetMixin路由才可以传参,前面说完了,我们来再次封装下代码:

    views下就变成了

    class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
    pass class BooksView(ModelViewSet):
    queryset = Book.objects
    serializer_class = BookModelSerializer

    urls下变成

    path('books', views.BooksView.as_view({"get": "list", "post": "create"})),
    re_path('book/(?P<id>\d+)', views.BooksView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),

    其实我们辗转了大半天,人家早就给我们封装好了,views下我们啥都不用写,就只需要继承人家封装好的就可以了,就下面几行代码即可

  • DRF视图最终写法
    from rest_framework import viewsets
    class BooksView(viewsets.ModelViewSet):
    queryset = Book.objects
    serializer_class = BookModelSerializer

    但是urls那里不能写id了,只能写pk

    path('books', views.BooksView.as_view({"get": "list", "post": "create"})),
    re_path('book/(?P<pk>\d+)', views.BooksView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
  1. DRF路由

    思考下,如果我们要写几十张表的路由,那岂不是又要每个路由传一堆一样的参数?别怕,DRF又帮我们搞定了,我们只需要按照下面的方式写即可

    from rest_framework.routers import DefaultRouter
    
    # 实例化DefaultRouter
    router = DefaultRouter()
    # 注册路由以及视图
    router.register(r"book", views.BooksView) # 将路由url加入到urlpatterns
    urlpatterns += router.urls

    该方法虽然简洁快速,但也会暴露很多路由接口,视情况选择使用.

最新文章

  1. 关于 WP 开发中.xaml 与.xaml.cs 的关系
  2. c#3.0新特性
  3. (转)Singleton 单例模式(懒汉方式和饿汉方式)
  4. 【GoLang】tcmalloc &amp;&amp; jemalloc
  5. Macbook pro内存升级
  6. CLR via C# 混合线程同步构造
  7. 3D Touch ? 木有6s,也阔以玩!!!
  8. noip2014总结
  9. iOS10隐私设置及相应问题
  10. HDU 5821 Ball
  11. .NET面试题目二
  12. JAVA的HashTable源码分析
  13. SQL中创建外键约束
  14. Git(3)----Eclipse上Git插件使用技巧
  15. Visionpro学习笔记 :QuickBuild-Based Application Run-Once Button
  16. Gcd&amp;Exgcd算法学习小记
  17. Java集合和数组的区别
  18. Linux内核修炼之framebuffer分析
  19. 2.两数相加(Add Two Numbers) C++
  20. super的使用方法与使用范围

热门文章

  1. string与QString转换(string既可以是utf8,也可以是gbk)
  2. Linux使用daemontools
  3. Kafka基本概念介绍
  4. spring之@Value详解(转载)
  5. github 上传更新代码(最简单的方法)
  6. 07 jQuery的位置信息
  7. 不用 qlv 格式转换成 mp4 - 优雅的下载腾讯视频(mp4 格式)
  8. 浅谈AI视频技术超分辨率
  9. SpringBoot系列——Logback日志,输出到文件以及实时输出到web页面
  10. 什么是Task