视图组件(继承不同类重写视图类第四层和第五层)、路由组件(修改路由的全部写法)

今日内容概要

  • 视图组件
  • 路由组件

内容详细

1、视图组件

# 9个视图子类--是视图类
from rest_framework.generics import 
    CreateAPIView, 
    ListAPIView, 
    DestroyAPIView, 
    RetrieveAPIView, 
    UpdateAPIView, 
    ListCreateAPIView, 
    RetrieveUpdateAPIView, 
    RetrieveUpdateDestroyAPIView, 
    RetrieveDestroyAPIView

第四层: 通过9个视图子类,重写视图函数 views.py:

# 第四层:通过9个视图子类,重写视图函数
# 9个视图子类
from rest_framework.generics import CreateAPIView, ListAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView


class PublishView(ListCreateAPIView):  # 查询所有和新增接口就有了
# class PublishView(CreateAPIView):  # 新增接口就有了
# class PublishView(ListAPIView):  # 查询所有接口就有了
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier


class PublishDetailView(RetrieveUpdateDestroyAPIView):  # 查询单条,删除,修改 接口就都有了
# class PublishDetailView(RetrieveAPIView):  # 查询单条 接口就有了
# class PublishDetailView(DestroyAPIView):  # 删除 接口就有了
# class PublishDetailView(UpdateAPIView):  # 修改 接口就有了
# class PublishDetailView(RetrieveDestroyAPIView):  # 查询单条和删除 接口就有了
# class PublishDetailView(RetrieveUpdateAPIView):  # 查询单条和更新 接口就有了
# class PublishDetailView(UpdateAPIView,DestroyAPIView):  # 更新和删除 接口就有了
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier

# 但是页有可能要重写--》get_queryset--》get_serializer_class--》perform_create--》get,post等方法

image

第五层: 通过ViewSet,重写视图函数 views.py:

# 第五层:通过ViewSet写视图类
# 5个接口,都用一个视图类----》导致了路由问题:有两个get
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet

"""
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.viewsets import ViewSetMixin
    ViewSet=APIView+ViewSetMixin
    GenericViewSet=GenericAPIView+ViewSetMixin
    
    以后只要想自动生成路由,必须继承ViewSetMixin及其子类
    之前的写法可以沿用,只是如果要自动生成路由可以选择继承ViewSet 或者 GenericViewSet
"""
class PublishView(ModelViewSet):  # 修改路由,5个接口都有
# 继承了5个视图扩展类+GenericViewSet(ViewSetMixin, generics.GenericAPIView)
# 其中 ViewSetMixin-->控制了路由写法变了

# class PublishView(ReadOnlyModelViewSet):  # 修改路由,只有 查所有,查单个两个接口
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier
    
    
    
##### 在urls.py中配置 加入方式一:
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('publish', views.PublishView, 'publish')
# 然后要把路由加入到urlpatterns的列表中 两种方式

urlpatterns = [
    path('admin/', admin.site.urls),

    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookView.as_view()),
]

# 加入方式一
# router.urls  他会自动生成列表 包含两种地址: publishs / publishs/<int:pk>
# print(router.urls)    # [<URLPattern '^publish/$' [name='publish-list']>, <URLPattern '^publish/(?P<pk>[^/.]+)/$' [name='publish-detail']>]
urlpatterns += router.urls   # 两个列表相加


##### 在urls.py中配置 加入方式二:
from django.urls import include
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('publish', views.PublishView, 'publish')
# 然后要把路由加入到urlpatterns的列表中 两种方式

urlpatterns = [
    path('admin/', admin.site.urls),

    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookView.as_view()),

    # 加入方式二:
    path('api/v1/', include(router.urls)),  # from django.urls import include
    # 这样写等用于下面两句  ''引号中可以随意加入前缀  # 但是默认就有: publishs / publishs/<int:pk>
    # path('api/v1/publishs/', views.PublishView.as_view()),
    #
    # path('api/v1/publishs/<int:pk>', views.PublishDetailView.as_view()),
]

image

2、路由组件

# 只要继承ViewSetMixin 及其子类,路由写法就变了

# 视图类只要继承ViewSetMixin,路由写法就变了 而且视图类中的方法不一定写成get,post.. 可以随意命名 路由改为:
        path('login/', views.TestView.as_view({'get': 'login'})),  # 意思为:get请求来了,执行视图类中的login方法
    
    
# 如何执行的?源码分析
    ViewSetMixin必须写在前面
    as_view--->类的查找顺序
    actions就是传入的字典---》view闭包函数:
def view(request, *args, **kwargs):
    #    get    login
    for method, action in actions.items():
        # 把login方法的内存地址给了handler
        handler = getattr(self, action)
        # 通过反射,设置给get---》对应login---》get请求执行get方法,现在get方法变成了login方法
        setattr(self, method, handler)
    return self.dispatch(request, *args, **kwargs)# 跟之前一样了

演示继承 ViewSetMixin类 的路由写法:

### views.py中:

from rest_framework.viewsets import ViewSetMixin, ViewSet, GenericViewSet
from rest_framework.views import APIView
from rest_framework.decorators import action

class TestView(ViewSetMixin, APIView):  # ViewSetMixin必须写在前面
# class TestView(ViewSet):  # 等同于上面 class TestView(ViewSetMixin, APIView)
# class TestView(ViewSetMixin, GenericAPIView):  # 只要继承ViewSetMixin的 该类就必须写在前面
    def login(self, request):
        return Response("get-login")
    
    
# 路由中 urls.py:
    # 路由组件:
    path('login/', views.TestView.as_view({'get': 'login'})),  # 意思为:get请求来了,执行视图类中的login方法

image

继承ModelViewSet 类,路由写法:

# views.py:

# 路由组件
class PublishView(ModelViewSet):  # 修改路由,5个接口都有
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier
    
    
# urls.py:

    path('publish/', views.PublishView.as_view({'get': 'list', 'post': 'create'})),
    path('publish/<int:pk>', views.PublishView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),

总结:

# 上面的两个路由,是可以自动生成的:
    第一步:导入drf提供的路由类
        from rest_framework.routers import SimpleRouter
        
    第二步:实例化得到对象
        router = SimpleRouter()
        
    第三步:注册路由
        router.register('地址', 视图类, '别名')
        router.register('publish', views.PublishView, 'publish')
        
    第四步:在urlpatterns加入(两种方式)
        path('/api/v1', include(router.urls))
        urlpatterns+=router.urls
        
        
# SimpleRouter类 和 DefaultRouter类 
    用法完全一样 只是生成的路由不一样
    DefaultRouter 比 SimpleRouter多一条根地址,一般咱么就用 SimpleRouter就可以
    
    
# 如果使用自动生成路由,必须继承谁及其子类?
    GenericViewSet + 5个视图扩展类至少之一 才能自动生成
    
    
# action装饰器
# action装饰器  可以再生成路由 记得要修改路由为自动生成模式
from rest_framework.decorators import action
class TestView(ViewSetMixin, APIView):  # ViewSetMixin必须写在前面
    # action的默认参数:
    # methods=请求方法,列表,  detail=是否带id,  url_path=地址如果不写,默认已方法名为地址,  url_name=别名
    # 写成如下,自动生成路由会生成一条路由:127.0.0.1:8080/test/login -->get,post都会触发
    @action(methods=['GET', 'POST'], detail=False)
    def login(self, request):
        return Response("get-login")
    
    # 如果写法如下,生成的路径是127.0.0.1:8080/test/数字/login
    @action(methods=['GET', 'POST'], detail=True)
    def login(self, request):
        
        
# 使用action,怎么通过action判断?
    重写 get_queryset、get_serializer_class
class TestView2(GenericViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get_queryset(self):
        # 根据请求地址,返回的get_queryset不一样
        if self.action=='login':
            return Author.objects.all()
        else:
            return self.queryset

    def get_serializer_class(self):
        if self.action=='login':
            return AuthorSerialzier
        else:
            return BookSerializer
        
    @action(methods=['GET','POST'],detail=True)
    def login(self,request):
        obj=self.get_queryset()
        return Response("get-login")

    @action(methods=['GET'], detail=True)
    def test1(self,request):
        obj = self.get_queryset()
        return Response("get-test1")

image