视图组件,路由组件,版本控制

1,视图组件

  • django中写CBV的时候继承View,rest_framework继承的是APIView,,其实APIView是继承View
urlpattEerns = [
    # url(r'^book$', BookView.as_view()),
    # url(r'^book/(?P<id>d+)', BookEditView.as_view()),
    
]

由此可以看出不论是django还是rest_framework用CBV的写法都是写as_view(),所以还是看一下源码吧,

APIView继承View,并执行view中的as_view的方法

 好,那我们看一下View中的as_view()都做了些什么

在重写的类中,或者继承的类中返回的方法,一定要搞清楚是谁调用的,执行方法的顺序是先从对象空间中寻找,在从子类中寻找,在从父类中寻找

我们看一下initialize_request方法和finalize_response方法都干了点啥...

重新封装request,说明request是Request的实例化对象

把request赋值给了self._request,说明_request是旧的request,那么request.GET和request.POST的方法的?

我们用了rest_framework框架后,我们的request是重新封装的Request类,request.query_params存放的是我们额get请求的参数mrequest',data存放的是我们所有的数据,包括post以及put,patch请求,相比原来的django的request,我们现在的request更加精简,清晰,

DRF视图的代码如下:

# ------------------------第一版的导入东西------------------
from rest_framework.views import APIView
from DrfDemo.models import Book
from DrfDemo.serializers import BookSerializer
from rest_framework.response import Response
# ----------------------------第二版需要导入的东西--------------------
from rest_framework.viewsets import ViewSetMixin
# ---------------------------第三版需要导入的东西---------------------
from rest_framework import viewsets


# ------------------------------------第一版一个一个类硬写----------------------------------
class BookView(APIView):
    # 定义一个get请求的方法
    def get(self,request):
        # 从数据库中获取数据
        book_queryset = Book.objects.all()
        # 用序列化器进行序列化(实例化序列化器的对象,把从数据库中提取出来的数据进行序列化)
        ser_obj = BookSerializer(book_queryset, many=True)
        # 返回这个经过序列化的对象
        return Response(ser_obj.data)

    # 手写一个post的方法(这里的post是新增)
    def post(self,request):
        # 1,确定数据类型以及数据结构
        # 2,对前端妹子传过来的数据进行校验
        book_obj = request.data  # 前端传过来的数据封装在data中
        # 把获取到的数据进行校验
        ser_obj = BookSerializer(data=book_obj)
        if ser_obj.is_valid():
            ser_obj.save()
            # 返回这个新增以后的数据
            return Response(ser_obj.validated_data)
        # 如果没成功则返回错误信息
        return Response(ser_obj.errors)


# 写一个更新的方法
class BookEditView(APIView):
    # 写一个get请求时处理get返回数据的
    def get(self, request, id):
        # 从数据库中匹配出要修改的数据对象
        book_obj = Book.objects.filter(id=id).first()
        # 拿到这个对象去序列化发送给前端
        ser_obj = BookSerializer(book_obj)
        # 返回给前端
        return Response(ser_obj.data)

    # 手写一个普通的方法
    def put(self, request, id):
        # 从数据库中拿到要编辑的数据
        book_obj = Book.objects.filter(id=id).first()
        # 把筛选出来的数据放到Bookserializer序列化器中做update用
        ser_obj = BookSerializer(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)

    # 手写一个删除的方法
    def delete(self, request, id):
        # 从数据库中拿到药删除的对象
        book_obj = Book.objects.filter(id=id).first()
        # 判断这个book_obj对象是否存在
        if not book_obj:
            return Response("删除的对象不存在")
        book_obj.delete()
        return Response("")

# --------------------------第二版高级一点,写成视图组件--------------------------------

# 写一个genericAPIView的类把代码中重复的代码提取出来
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    # 自定义get_queryset的方法
    def get_queryset(self):
        return self.queryset.all()

    # 自定义get_serializer的方法
    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


# 定义ListModelMixin类
class ListModelMixin(object):
    # 定义一个get请求的方法
    def list(self, request):
        # 执行get_queryset()的方法(从数据库中获取数据)
        queryset = self.get_queryset()
        # 执行get_serializer方法(去序列化器序列化)
        ser_obj = self.get_serializer(queryset, many=True)
        # 返回ser_obj.data序列化的对象
        return Response(ser_obj.data)


# 定义增加的类CreateModelMixin
class CreateModelMixin(object):
    # 写一个创建的方法
    def create(self, request):
        # 获取前端传过来的数据(是反序列化后的数据)
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            # 通过校验后,ORM操作完以后save()到数据库中
            ser_obj.save()
            # 返回这个通过校验的数据
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)


# 定义一个单条数据的查看
class RetrieveModelMixin(object):
    # 从数据库中查出单条数据
    def retrieve(self, request, id):
        # 从数据库中获取要查询的这个单条数据
        book_obj = self.get_queryset().filter(id=id).first()
        # 把这个对象序传到序列化器进行序列化
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)


# 手写一个update的类去编辑数据
class UpdateModelMixin(object):
    # 手写一个更新数据的方法
    def update(self, request, id):
        # 从数据库中匹配出要修改的数据对象
        book_obj = self.get_queryset().filter(id=id).first()
        # 拿到要修改的数据和从数据库中匹配出来的数据放到序列化器去进行ORM操作
        ser_obj = self.getserializer(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)


# 手写一个DestroyModelMixin的删除的类
class DestroyModelMixin(object):
    # 写一个删除的方法
    def destroy(self, request, id):
        # 先从数据库中获取要删除的对象
        book_obj = self.get_queryset().filter(id=id).first()
        # 先判断是否存在要删除的对象
        if not book_obj:
            return Response("删除的对象不存在")
        # 如果有book_obj删除的对象就进行删除操作
        return Response("")  # 删除成功就返回一个空的字符串


# 写一个ListCreateAPIView的类来继承genericAPIView, ListModelMixin, CreateModelMicxin
# 这样就是的ListCreateAPIView这个类就有了继承类的方法和属性
# 这是新增,增加用的
class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    pass


# 这个是增加用的类要封装GenericAPIView和RetrieveModelMixin和UpdateModelMixin和DestroyModelMixin
class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass


# 就是为了把上边2个继承以后,都了他们的方法和属性
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
    pass


# 正式的视图函数
# 里边包括查看多条数据和增加数据
class BookView(ListCreateAPIView):
    # 先查出书籍的对象集合
    # versioning_class =
    queryset = Book.objects.all()
    # 调用序列化器
    serializer_class = BookSerializer
    # 查看多条数据的方法

    def get(self, request):
        print(request.version)
        # 返回list的方法此时的self是BookView实例化的对象
        return self.list(request)

    # 执行新增的方法
    def post(self, request):
        return self.create(request)


# 写一个编辑的类(编辑和删除, 查看单条数据)
class BookEditView(RetrieveUpdateDestroyAPIView):
    # 先从数据库中获取要操作的数据对象
    queryset = Book.objects.all()
    # 启用序列化器,把序列化器这个类赋值给serializer
    serializer_class = BookSerializer

    # 定义一个get方法
    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)

# 总结:1,先把需要查看所有的信息和增加的类定义好,把查看单条信息和更新删除的方法的类,然后各自返回要执行的操作方法
#      2,把 需要展示的数据从数据库中读取出来,并且要用序列化器进行序列化或者反序列化嗨哟偶就是校验等ORM操作
#      3,返回这些操作的时候按照类继承的顺序去找到这些方法,并执行相应的方法注意类继承的查找顺序


# -----------------------第三版直接用人家写好的ViewSet--------------------------------
class BookModelView(viewsets.ModelViewSet):
    # 先从数据库中读取书籍的对象集合
    queryset = Book.objects.all()
    # 调用序列化器
    serializer_class = BookSerializer

view中类的继承示意图

2,路由组件

因为有框架,帮我们封装的非常简单,路由呢,不需要一一去注册路由,我们有路由组件

from django.conf.urls import url
from DrfDemo import views
from DrfDemo.views import BookModelView
# 1,帮我们生成带参数的路由 (用默认的路由DefaultRouter)
from rest_framework.routers import DefaultRouter
# 2,实例化一个 默认路由的对象
router = DefaultRouter()
# 3,用水利化的对象去注册我们的路由以及视图
router.register(r'^book/', BookModelView)
# 4,要将urlpatterns添加注册的路由
urlpatterns = [
    url(r'^book/$', views.BookView.as_view()),
    url(r'^book/(?P<id>d+)/', views.BookEditView.as_view())
]
# 这是个啥意思?没明白???,   列表支持这样的语法操作
# urlpatterns += router.urls

 3,DRF版本的控制

版本是什么,我们为什么要用版本控制?

  • 首先我们要知道版本是干嘛的呢~~大家都知道我们开发项目是有很多版本的~~当我们项目过一段时间就更新(修改bug和增加新的功能)~~我们不可能出了新的版本,就不再使用旧得版本,我们就需要对版本进行控制

版本控制怎么用?

我们看一下源码的dispatch()方法

self.initial下边是路由的分发,那么就看self.initial做了一些什么事...

由源码可知:

vsersion版本信息赋值给了request.version中了,版本控制方案赋值给了request_versioning_scheme~~,其实这个版本控制方案,就是配置的版本控制类

我们看一下rest_framework提供了那些版本控制方法

from rest_framework import versioning

因此determine_version这个方法要重写

代码如下:

1,url的代码:

from django.conf.urls import url
from VerisonDemo import views

urlpatterns = [
    url(r'^demo/', views.VersionDemo.as_view()),
]

2,utils里的版本控制代码:

class MyVersion(object):
    def determine_version(self, request, *args, **kwargs):
        # 方法的返回值是版本号
        # 获取前端传过来的版本号,并且把版本号返回
        version = request.query_params.get("version")
        print("version", version)
        # 判断从前端获取的数据是否存在version
        if not version:
            print("版版本组件",version)
            # 如果不存在version即表示用户没有指定版本号可以指定一个默认的版本号
            version = "v1"
        # 最后不论存不存在都要返回这个版本
        return version  # 返回的这个version存在于request中

3视图函数的业务逻辑代码:

from rest_framework.views import APIView
from rest_framework.response import Response
from DRFDemo.utils.version import MyVersion

# Create your views here.


class VersionDemo(APIView):
    versioning_class = MyVersion
    print(123)
    # get请求
    def get(self, request):

        print("request.version", request.version)  # 这拿到的是Version中的v1
        print("request.versioning_scheme",request.versioning_scheme)  # 这拿到的是MyVersion的内存地址
        # 根据版本号处理不同业务逻辑
        if request.version == "v2":
            return Response("这是版本v2返回的信息")
        return Response("这是版本v1返回的信息")

其他版本控制类的配置,和这个大同小异.

原文地址:https://www.cnblogs.com/ljc-0923/p/10265342.html