视图与路由组件

由APIView到视图集

from django.shortcuts import render
from rest_framework.generics import GenericAPIView
from rest_framework.parsers import JSONParser
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
from rest_framework.viewsets import ModelViewSet, ViewSetMixin, ViewSet

from .models import Book, Author, AuthorDetail, Publish
from rest_framework.response import Response
from .serializer import BookSerializer, PublishSerializer,users
from rest_framework.views import APIView


# Create your views here.
# 基于 APIView
class BookAPIView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 10000, 'msg': '增加成功'})
        else:
            return Response({'code': 10001, 'msg': '增加失败'})


class BookAPIViewt(APIView):
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 10000, 'msg': '修改成功'})
        else:
            return Response({'code': 10001, 'msg': '修改失败'})

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 10000, 'msg': '删除成功'})


# 基于GenericAPIView类
# 继承自APIVIew
# 主要增加了操作序列化器和数据库查询的方法
# 为下面Mixin扩展类的执行提供方法支持
class BookView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        list = self.get_queryset()
        ser = self.get_serializer(instance=list, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 10000, 'msg': '增加成功'})
        else:
            return Response({'code': 10001, 'msg': '增加失败'})


class BookViewt(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, pk):
        book = self.get_queryset().filter(pk=pk).first()
        ser = self.get_serializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = self.get_queryset().filter(pk=pk).first()
        ser = self.get_serializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 10000, 'msg': '修改成功'})
        else:
            return Response({'code': 10001, 'msg': '修改失败'})

    def delete(self, request, pk):
        self.get_queryset().filter(pk=pk).delete()
        return Response({'code': 10000, 'msg': '删除成功'})


# 基于Mixin类
# 继承自GenericAPIView
# 实现了几种后端视图(对数据资源进行曾删改查)处理流程的实现
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
    DestroyModelMixin


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

    def get(self, request):
        return super().list(request)

    def post(self, request):
        return super().create(request)


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

    def get(self, request, pk):
        return super().retrieve(request, pk)

    def put(self, request, pk):
        return super().update(request, pk)

    def delete(self, request, pk):
        return super().destroy(request, pk)


# 基于GenericAPIView的视图子类
# 是对modelmixin类的组合
from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView

from rest_framework.generics import RetrieveAPIView, UpdateAPIView, DestroyAPIView

from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView


class BookViewv(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class BookViewvt(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


# 视图集 同样是对modelmixin类的组合 但是多继承了一个ViewSetMixin
# 提供一个action方法
# 通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。
# 以后写视图类,继承ViewSetMixin及其子类,路由写法就变了
class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


# action装饰器的用法
from rest_framework.decorators import action
class P(ViewSet):
    @action(methods=['POST','GET'], detail=False, url_path='y')
    def y(self,request):
        return Response('y')

2个视图基类

# django 内置的View
# drf 的APIView ,继承自View
# GenericAPIView
	-两个重要的类属性:
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类
    -几个重要的方法:
    self.get_object()   
    self.get_queryset()  
    self.get_serializer(instance=book_list, many=True)
    	

1.1 使用APIView写5个接口

class BookView(APIView):
    def get(self,request):
        book_list=Book.objects.all()
        # 如果写了many=True,ser是哪个类的对象?
        ser=BookSerializer(instance=book_list,many=True)
        print(type(ser)) # ListSerializer的对象---》[BookSerializer,BookSerializer,BookSerializer]
        return Response(ser.data)

    def post(self,request):
        ser=BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':'100','msg':'创建成功'})
        else:
            return Response({'code': '101', 'msg': '创建失败','err':ser.errors})

class BookDetailView(APIView):
    def get(self,request,*args,**kwargs):  # pk 从kwargs中去
        book=Book.objects.filter(pk=kwargs['pk']).first()
        # 如果写了many=True,ser是哪个类的对象?
        ser=BookSerializer(instance=book)
        print(type(ser))  # BookSerializer的对象
        return Response(ser.data)

    #put:全局修改   patch:局部修改
    def put(self,request,*args,**kwargs):  # pk 从kwargs中去
        book=Book.objects.filter(pk=kwargs['pk']).first()
        ser=BookSerializer(instance=book,data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': '100', 'msg': '创建成功'})
        else:
            return Response({'code': '101', 'msg': '创建失败', 'err': ser.errors})

1.2 继承GenericAPIView写5个接口

class BookView(GenericAPIView):
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类

    def get(self, request):
        print('dsafdasdfasd')
        book_list = self.get_queryset()  # 获取要序列化的数据,不要直接使用self.queryset,而要用self.get_queryset()

        # 获取序列化类,要使用self.get_serializer
        ser = self.get_serializer(instance=book_list, many=True)
        print(type(ser))  # ListSerializer的对象---》[BookSerializer,BookSerializer,BookSerializer]
        return Response(ser.data)

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': '100', 'msg': '创建成功'})
        else:
            return Response({'code': '101', 'msg': '创建失败', 'err': ser.errors})


class BookDetailView(GenericAPIView):
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类
    #传入的必须叫pk,否则,get_object就拿不到对象
    def get(self, request, *args, **kwargs):
        # 获取单个对象,
        book = self.get_object()
        # 如果写了many=True,ser是哪个类的对象?
        ser = self.get_serializer(instance=book)
        print(type(ser))  # BookSerializer的对象
        return Response(ser.data)

    # put:全局修改   patch:局部修改
    def put(self, request, *args, **kwargs):  # pk 从kwargs中去
        book = self.get_object()
        ser = self.get_serializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': '100', 'msg': '创建成功'})
        else:
            return Response({'code': '101', 'msg': '创建失败', 'err': ser.errors})

2 5 个视图扩展类

# 视图扩展类---》不是视图类---》没有继承视图类(View,APIView...子类)
ListModelMixin,  #获取所有
CreateModelMixin,#创建一个
RetrieveModelMixin,#查询一个
UpdateModelMixin,#更新一个
DestroyModelMixin#删除一个
# class ListModeMixin():
#     def list(self, request):
#         print('dsafdasdfasd')
#         book_list = self.get_queryset()  # 获取要序列化的数据,不要直接使用self.queryset,而要用self.get_queryset()
#
#         # 获取序列化类,要使用self.get_serializer
#         ser = self.get_serializer(instance=book_list, many=True)
#         print(type(ser))  # ListSerializer的对象---》[BookSerializer,BookSerializer,BookSerializer]
#         return Response(ser.data)

from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class BookView(GenericAPIView,ListModelMixin,CreateModelMixin):
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类

    def get(self,request):
        print('获取所有')
        return super().list(request)



    def post(self, request):
        return super().create(request)


class BookDetailView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类
    #传入的必须叫pk,否则,get_object就拿不到对象
    def get(self, request, *args, **kwargs):
        print('获取一')
        return super().retrieve(request, *args, **kwargs)

    # put:全局修改   patch:局部修改
    def put(self, request, *args, **kwargs):  # pk 从kwargs中去
        return super().update(request, *args, **kwargs)

    def delete(self,request, *args, **kwargs):
        return super().destroy(request, *args, **kwargs)

3 9个视图子类

# 获取所有,新增一个,获取所有和新建一个
ListAPIView,CreateAPIView,ListCreateAPIView

# 获取单个,更新一个,删除一个
RetrieveAPIView,UpdateAPIView,DestroyAPIView
# 
RetrieveUpdateDestroyAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView

# 继承9个视图子类后,只需要在视图类中写两个类属性即可

class BookView(ListCreateAPIView):  # 获取所有和新增一个
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类

class BookDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()  # 要序列化的数据
    serializer_class = BookSerializer  # 序列化类

4 视图集

ModelViewSet=
	# 5个视图扩展类---》每个类里有一个方法 list,create,retrieve,destory,update
	mixins.CreateModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
    mixins.ListModelMixin,
    # ViewSetMixin:特点,只要继承它,路由写法变了,变成了:as_view({'get': 'list', 'post': 'create'}---》请求方式和方法的对应关系
    # generics.GenericAPIView 2个视图基类中得一个
    GenericViewSet
    	-ViewSetMixin+GenericAPIView
    
    
# ViewSetMixin 源码分析
class ViewSetMixin:
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        # actions={'get': 'list', 'post': 'create'}
        def view(request, *args, **kwargs):
            #   method:get      action:list
            for method, action in actions.items():
                # handler就是list
                handler = getattr(self, action) #视图类反射有没有list
                # 反射:把get变成了list
                setattr(self, method, handler)
            return self.dispatch(request, *args, **kwargs)
        return csrf_exempt(view)
# 如果请求来了,会执行 view(request)
# 视图集中的类
	-ModelViewSet
    -ReadOnlyModelViewSet
    -ViewSetMixin
    -ViewSet   :ViewSetMixin+APIView
    -GenericViewSet:ViewSetMixin+GenericAPIView
    
# 以后你想继承APIView,但是路由想自动生成,继承ViewSet
# 以后想继承GenericViewSet,但是路由想自动生成,GenericViewSet

5 路由组件

# 1 继承了ViewSetMixin及其子类,路由写法变了
	-写法一:path('publish', views.PublishView.as_view({'get': 'lqz','post':'login'})),
    -写法二:自动生成
    # 第一步:导入一个路由类
    from rest_framework.routers import SimpleRouter, DefaultRouter

    # 第二步:实例化得到对象
    router=SimpleRouter()
    # router = DefaultRouter()  # 它会给每个注册的视图类都生成一个根路由
    # 第三步:注册路由---》使用视图类注册---》能自动生成路由
    router.register('books', views.BookView, 'books')
    router.register('publish', views.BookView, 'publish')
    # 第四步:在总路由中注册  方式二
    path('', include(router.urls)),
    # 第四步:在总路由中注册  方式一
	# urlpatterns+=router.urls
    
    
# action装饰器的用法
	-之前自动生成路由只能生成
    {'get': 'list', 'post': 'create'},{'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}
    -使用action装饰器来做对应关系
        '''
        methods:请求方式
        detail:
            False:是不是带id的路由  http://127.0.0.1/publish/3   http://127.0.0.1/publish
            True: 生成的路由publish/pk/lqz/
        url_path:如果不写,就是函数名生成的路径是:http://127.0.0.1/publish/lqz
        url_name:别名
        '''

5.1 路由

path('publish', views.PublishView.as_view({'get': 'lqz','post':'login'})),

5.2 视图类

class PublishView(ViewSetMixin,APIView):  # 路由写法变了,变成映射关系了,在视图类中可以写任意的方法名
    def lqz(self,request):
        return Response('lqz')
    def login(self,request):
        return Response('login')
posted @ 2022-06-20 21:59  Rain_Kz  阅读(37)  评论(0)    收藏  举报