DRF的视图和路由

DRF的视图

APIView

Django中写CBV的时候继承的是View,rest_framework继承的是APIView,

urlpatterns = [
    url(r'^book$', BookView.as_view()),
    # url(r'^book/(?P<id>d+)', BookEditView.as_view()),
    url(r'^book$', BookModelView.as_view({"get": "list", "post": "create"})),
    # url(r'^book/(?P<pk>d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

View和APIView调用的都as_view()方法,我们知道APIView继承了View,并且重写了as_view()方法,并执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。看下图:

APIView还执行了dispatch方法,新的request是Request类的实例化对象,看下图:

我们看看initialize_request中的代码实现了什么功能:

点击Request可以看到Request类把原来的request赋值给了self._request,也就是说以后_request是我们旧的request,看下图:

继承APIVIew之后的请求来的数据,看下图:

当用了rest_framework框架后,我们的request是重新封装的Request类

request.query_params存放的是我们get请求的参数

request.data存放的是我们所有的数据,包括post请求的以及put,patch请求

相比原来的Django的request,我们现在的request更加精简,清晰了

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

所以我们需要封装一下。

第一次封装

因为代码中除了序列化器不同以及获取的queryset对象不同,其他的都类似。所有我们它相同的代码封装出来,提高代码的复用性。

  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("删除的书籍不存在")

  第一次封装

from django.shortcuts import render
from rest_framework.views import APIView
from djangoDemo.models import Book
from .serializers import BookSerializer
from rest_framework.response import Response


# queryset不同
# 序列化器不同
# def get():
# def post():

class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        # 放到缓存中再拿出来时就需要我们用all()来获取,这是Django机制导致的
        return self.queryset.all()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class ListModelMixin(object):
    def list(self, request):
        # 调用外部的get方法
        # 执行父类的方法
        queryset = self.get_queryset()
        # 实例化序列化器
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


class CreateModelMixin(object):
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            # 校验过的数据存放在validated_data中
            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)


class UpdateModelMixin(object):
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        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)


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.delete()
        return Response('')


class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        # 封装ListModelMixin类以后的执行过程
        return self.list(request)

        # 只封装GenericAPIView类的执行过程
        # # 调用外部的get方法
        # # 执行父类的方法
        # queryset = self.get_queryset()
        # # 实例化序列化器
        # ser_obj = self.get_serializer(queryset, many=True)
        # return Response(ser_obj.data)

        # 没封装之前
        # book_queryset = Book.objects.all()
        # 用序列化器进行序列化
        # ser_obj = BookSerializer(book_queryset, many=True)
        # 通过点data来获取数据
        # return Response(ser_obj.data)

    # 没封装前的post执行过程
    # def post(self, request):
    #     # 获取从前端传递过来的值
    #     book_obj = request.data
    #     # data=book_obj就是反序列化时的对象数据
    #     ser_obj = BookSerializer(data=book_obj)
    #     if ser_obj.is_valid():
    #         ser_obj.save()
    #         # 反序列化以后的数据放在validated_data中
    #         return Response(ser_obj.validated_data)
    #     # 如果校验不成功则返回错误信息
    #     return Response(ser_obj.errors)

    # 继承CreateModelMixin类后的post执行过程
    def post(self, request):
        return self.create(request)


class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # ser_obj = BookSerializer(book_obj)
        # return Response(ser_obj.data)
        return self.retrieve(request, id)

    def put(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # 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)
        return self.update(request, id)

    def delete(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # if not book_obj:
        #     return Response('删除的数据不存在')
        # book_obj.delete()
        # return Response('')
        return self.destroy(request, id)

第二次封装

# 我们把继承的类封装了一下
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):
        # 封装ListModelMixin类以后的执行过程
        return self.list(request)
 
    # 继承CreateModelMixin类后的post执行过程
    def post(self, request):
        return self.create(request)
 
 
class BookEditView(RetrieveUpdateDestroyAPIView):
    queryset = 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)

 第三次封装

我们可不可以把这两个视图合并成一个视图呢~~~框架给我们提供了一个路由传参的方法~~

actions这个默认参数其实就是我们路由可以进行传参了~~~

下面这个循环~可以看出~我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法~

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

  路由urls.py

from django.conf.urls import url, include
from .views import BookView, BookEditView, BookModelView
# 帮助我们生成带参数的路由
from rest_framework.routers import DefaultRouter
# 实例化DefaultRouter对象
router = DefaultRouter()
# 注册我们的路由以及视图
router.register(r'^book', BookModelView)


urlpatterns = [
    url(r'^book$', BookView.as_view()),
    # url(r'^book/(?P<id>d+)', BookEditView.as_view()),
    url(r'^book$', BookModelView.as_view({"get": "list", "post": "create"})),
    # url(r'^book/(?P<pk>d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
    
]

urlpatterns += router.urls

  第三次封装

ViewSetMixin  重写了as_view()方法

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer
from rest_framework.viewsets import ViewSetMixin


from rest_framework import views  # APIView
from rest_framework import viewsets
from rest_framework import generics
from rest_framework import mixins


# 自定义了一个类,
class ModelViewSet(ViewSetMixin, ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass


# 然后继承它
class BookModelView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

  由于第三次封装所以路由发生了改变:

from django.conf.urls import url, include
from .views import BookView, BookEditView, BookModelView

urlpatterns = [
    url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})),
    url(r'^book/(?P<pk>d+)/',
        BookModelView.as_view({"get": "list", "post": "create", "put": "update", "delete": "destroy"})),
]

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

看看我们的继承顺序

DRF的路由

路由

from django.conf.urls import url, include
from .views import BookView, BookEditView, BookModelView

# 帮我们生成带参数的路由(我们原本是不能传递参数的在路由中)
from rest_framework.routers import DefaultRouter

# 实例化DefaultRouter对象
router = DefaultRouter()

# 注册我们的路由以及视图
router.register(r'book', BookModelView)


urlpatterns = [
    # url(r'^book/$', BookView.as_view()),
    # url(r'^book/(?P<pk>d+)/', BookEditView.as_view()),
    # url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})),
    # url(r'^book/(?P<pk>d+)/',
        # BookModelView.as_view({"get": "list", "post": "create", "put": "update", "delete": "destroy"})),
]

urlpatterns += router.urls

  需要自定制的时候还是需要我们自己用APIView写~~当不需要那么多路由的时候~也不要用这种路由注册~~

  

原文地址:https://www.cnblogs.com/wjs521/p/9976307.html