视图组件与路由组件

视图组件与路由组件

一 视图组件

1 drf视图类

# Django REST framwork 提供的视图的主要作用:
    控制序列化器的执行(检验、保存、转换数据)
    控制数据库查询的执行

2 2个视图基类

2.1 DRF视图基类

# REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。

2.2 视图基类的基本情况

2.2.1 APIView
1) # APIView:继承了原生Django的View, 是REST framework提供的所有视图的基类

2) # APIView与View的不同之处在于:
    -传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
	-视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
	-任何APIException异常都会被捕获到,并且处理成合适的响应信息;
	-在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

3) #支持定义的类属性
    -authentication_classes  列表或元祖,身份认证类
    -permissoin_classes      列表或元祖,权限检查类
    -throttle_classes        列表或元祖,流量控制类

4) #基本使用:
	-在APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
2.2.2 GenericAPIView通用视图类
1) # GenericAPIView:继承了APIView
# 主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。

2) # 提供的关于序列化器使用的属性与方法
2.1) #属性
	-queryset = models.Book.objects.all()  # 指明使用的数据查询集

    -serializer_class = serializer.BookModelSerializer  # 指明视图使用的序列化器

2.2) #方法
    -get_queryset(self):获取配置的queryset
	# 返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,

    -get_object(self):路由中的分组字段必须是pk
	# 返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
	# 在视图中可以调用该方法获取详情信息的模型类对象。
	# 若详情访问的模型类对象不存在,会返回404。
	# 该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

    -get_serializer(self, *args, **kwargs):
    # 返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
	 
2.2.3 总结**
# APIView:继承了原生Django的View
# GenericAPIView:继承了APIView

# 最终总结
# 两个基类
APIView:如果跟models没有关系(没有数据库相关操作),就继承它
GenericAPIView:有关数据库操作,queryset 和serializer_class

2.3 使用示例:APIView

models

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32, null=True)
    price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
    publish = models.CharField(max_length=32, null=True)

serializer.py

from app01 import models
from rest_framework import serializers

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'

view

### 继承了APIView
class BookAPIView(APIView):
    def get(self, request):
        book_list = models.Book.objects.all()
        ser = serializer.BookModelSerializer(book_list, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = serializer.BookModelSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('成功!')

class BookDetailAPIView(APIView):
    def get(self, request, pk):
        book = models.Book.objects.get(id=pk)
        ser = serializer.BookModelSerializer(book)
        return Response(ser.data)

    def put(self, request, pk):
        book = models.Book.objects.get(id=pk)
        ser = serializer.BookModelSerializer(book, data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('修改成功')

    def delete(self, requset, pk):
        models.Book.objects.filter(id=pk).delete()
        return Response('删除成功')

2.4 使用示例:GenericAPIView

models

# 同上

serializer

# 同上

view

## 继承了GenericAPIView
class BookGenericView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    def get(self, request, *args, **kwargs):
        obj = self.get_queryset()
        ser = self.get_serializer(obj, many=True)
        return Response(ser.data)

    def post(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('成功')

class BookDetailGenericView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    def get(self, request, *args, **kwargs):
        obj = self.get_object()
        ser = self.get_serializer(obj)
        return Response(ser.data)

    def put(self, request, *args, **kwargs):
        obj = self.get_object()
        ser = self.get_serializer(obj, data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('修改成功')

    def delete(self, request, *args, **kwargs):
        self.queryset.filter(id=kwargs.get('pk')).delete()
        return Response('删除成功')

3 5个视图扩展类

3.1 五个视图扩展类及其作用

3.1.1 5个视图扩展类
# (rest_framework.mixins)
1) CreateModelMixin:    create方法创建一条
	-提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。

2) DestroyModelMixin:   destory方法删除一条
	-提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。

3) ListModelMixin:      list方法获取所有
	-提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。【该Mixin的list方法会对数据进行过滤和分页。】

4) RetrieveModelMixin:  retrieve获取一条
	-提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。

5) UpdateModelMixin:    update修改一条
	-提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。
3.1.2 作用:
	-提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
	-这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

3.2 自定义视图扩展类

# 自定义视图扩展类
class ListView():
    def get(self, request, *args, **kwargs):
        obj = self.get_queryset()
        ser = self.get_serializer(obj, many=True)
        return Response(ser.data)

class CreateView():
    def post(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('成功')

class BookGenericView(GenericAPIView, ListView, CreateView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

class RetrieveView():
    def get(self, request, *args, **kwargs):
        obj = self.get_object()
        ser = self.get_serializer(obj)
        return Response(ser.data)

class UpdateView():
    def put(self, request, *args, **kwargs):
        obj = self.get_object()
        ser = self.get_serializer(obj, data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('修改成功')

class DestotyView():
    def delete(self, request, *args, **kwargs):
        self.queryset.filter(id=kwargs.get('pk')).delete()
        return Response('删除成功')

class BookDetailGenericView(GenericAPIView, RetrieveView, UpdateView, DestotyView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

3.3 使用drf提供的视图扩展类

##5个视图扩展类
from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin

class BookGenericAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.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 BookDetailGenericAPIView(GenericAPIView, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

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

4 9个子类视图

4.1 9个子类视图及其方法

#(rest_framework.generics)
1) CreateAPIView:
    -继承CreateModelMixin,GenericAPIView
    -有post方法,新增数据
2) DestroyAPIView:
	-继承DestroyModelMixin,GenericAPIView
    -有delete方法,删除数据
3) ListAPIView:
	-继承ListModelMixin,GenericAPIView
    -有get方法获取所有
4) UpdateAPIView:
	-继承UpdateModelMixin,GenericAPIView
    -有put和patch方法,修改数据
5) RetrieveAPIView:
	-继承RetrieveModelMixin,GenericAPIView
    -有get方法,获取一条
>>-----------------------------------<<
6) ListCreateAPIView:
	-继承ListModelMixin,CreateModelMixin,GenericAPIView
    -有get获取所有,post方法新增
7) RetrieveDestroyAPIView:
	-继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView
    -有get方法获取一条,delete方法删除
8) RetrieveUpdateAPIView:
	-继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView
    -有get获取一条,put,patch修改
9) RetrieveUpdateDestroyAPIView:
	-继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView
    -有get获取一条,put,patch修改,delete删除

4.2 使用示例

from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView,  RetrieveUpdateDestroyAPIView

# # class BookGenericAPIView(CreateAPIView):
# # class BookGenericAPIView(ListAPIView):
class BookGenericAPIView(ListCreateAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
    
# # class BookDetailGenericAPIView(RetrieveAPIView):
# # class BookDetailGenericAPIView(RetrieveAPIView,UpdateAPIView):
class BookDetailGenericAPIView(RetrieveUpdateDestroyAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

5 视图集类

#视图集类

# ViewSetMixin:重写了as_view 

# ViewSet:     继承ViewSetMixin和APIView
# GenericViewSet:继承ViewSetMixin, generics.GenericAPIView

# ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
# ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet

5.1 关于视图集类

-使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
    ·list() 提供一组数据
    ·retrieve() 提供单个数据
    ·create() 创建数据
    ·update() 保存数据
    ·destory() 删除数据

-ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。

-视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。

5.2 ViewSet与GenericViewSet

5.2.1 ViewSetMixin
# 源码
class ViewSetMixin:
    """
    This is the magic.

    Overrides `.as_view()` so that it takes an `actions` keyword that performs the binding of HTTP methods to actions on the Resource.

    For example, to create a concrete view binding the 'GET' and 'POST' methods to the 'list' and 'create' actions...

    view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
    """
5.2.2 ViewSet
    -继承ViewSetMixin 【重写了as_view 】 和APIView
    
    -作用与APIView基本类似,提供了身份认证、权限校验、流量管理等。
    
    -ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。

    -在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

# 源码
class ViewSet(ViewSetMixin, views.APIView):
    """
    The base ViewSet class does not provide any actions by default.
    """
    pass
5.2.3 GenericViewSet
    -继承ViewSetMixin, generics.GenericAPIView
    
    -在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。
    
    -使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖于 GenericAPIView,所以还需要继承GenericAPIView。

# 源码
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default, but does include the base set of generic view behavior, such as the `get_object` and `get_queryset` methods.
    """
    pass

5.3 ModelViewSet与ReadOnlyModelViewSet

5.3.1 ModelViewSet
    -继承GenericViewSet
    -同时包括了mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin
5.3.2 ReadOnlyModelViewSet
    -继承GenericViewSet
    -同时包括了GenericViewSetmixins.RetrieveModelMixin,mixins.ListModelMixin,

5.4 视图集类之action的使用**

5.4.1 action 的作用
-在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个。
5.4.2 action的用法
# 只要继承了ViewSetMixin类
# 路由配置:path('books_mix/', views.BookView.as_view({'get':'lqz'}))
# 视图类的方法中就会有个action
class BookView(ViewSet):
    def lqz(self,request,*args,**kwargs):
        print(self.action)
        return Response('lqz')    
    
# ViewSetMixin以后只要继承它,路由的配置就发生变化了,只需要写映射即可
5.4.3 使用示例-action

url

    path('books_mix1', views.BookView.as_view({'get': 'lxx'})),
    path('books_mix2', views.BookView.as_view({'get': 'exon'})),

views

from rest_framework.viewsets import ViewSetMixin, ViewSet

# class BookView(ViewSetMixin, APIView):
class BookView(ViewSet):
    def lxx(self, request, *args, **kwargs):
        print(self.action)  # lxx
        return Response('lxx')

    def exon(self, request, *args, **kwargs):
        return Response('exon')
5.4.4 使用示例-ModelViewSet

url

## 路由
    ## 使用视图集
    path('books_set/', views.BookSetView.as_view({'get': 'list', 'post': 'create'})),
    # # path('books_set/', views.BookSetView.as_view()), # 直接报错
    re_path('^books_set/(?P<pk>\d+)', views.BookSetView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),

views

# 继承一个东西,有5个接口
from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import ReadOnlyModelViewSet  # 只有查询
from rest_framework.views import APIView

class BookSetView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

二 路由组件

1 路由Routers

# 自动生成路由:REST framework提供了两个router, 来帮助我们快速实现路由信息。
    -SimpleRouter
    -DefaultRouter
# 配置路由的三种方式
1)-最原始的
	-path('books/', views.BookAPIView.as_view()),

2)-ViewSetMixin的视图类
    -path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'}))

3)-ViewSetMixin的视图类
    -自动生成,见下面:Routers自动生成路由

2 自动生成路由的两种方法

2.1 Routers自动生成路由

# 继承了ViewSetMixin的视图类,以后写路由,可以自动生成
from rest_framework import routers
# 实例化得到一个对象
router = routers.SimpleRouter()
# 注册进路由    
router.register('books', views.BookSetView)
# 把自动生成的路由配置到urlpatterns中
	-urlpatterns += router.urls
    -re_path(r'v1/', include(router.urls))

2.2 action装饰器自动生成路由

# action
-当自动生成路由的时候,如果视图类中还有【其它方法】,是无法自动生成路由的
-加action装饰器:
	-methods:什么请求方式会触发被装饰函数的执行
	-detail:是True是基于带id的路由生成的,如果是False,是基于不带id的路由生成的
	-@action(methods=['get'], detail=True)

2.3 自动生成路由的配置方式

urls

from rest_framework import routers

# 实例化得到一个对象
router = routers.SimpleRouter()
# router = routers.DefaultRouter()
router.register('books', views.BookSetView, basename='book')  # basename='book'是别名
print(router.urls)
# [<URLPattern '^books/$' [name='book-list']>,
# <URLPattern '^books/lxx/$' [name='book-lxx']>,
# <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='book-detail']>,
# <URLPattern '^books/(?P<pk>[^/.]+)/login/$' [name='book-login']>]

urlpatterns = []
urlpatterns += router.urls

2.4 action装饰器的使用

views

from rest_framework.decorators import action

class BookSetView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    @action(methods=['get'], detail=True)
    def login(self, request, *args, **kwargs):
        print(args)  # ()
        print(kwargs)  # {'pk': '5'}
        print(self.action)  # login
        return Response('XXXX')

    @action(methods=['post'], detail=False)
    def lxx(self, request, *args, **kwargs):
        print(self.action)  # lxx
        return Response('lxx')
posted @ 2021-06-28 06:30  越关山  阅读(99)  评论(0)    收藏  举报