1. 程式人生 > 其它 >檢視元件(繼承不同類重寫檢視類第四層和第五層)、路由元件(修改路由的全部寫法)

檢視元件(繼承不同類重寫檢視類第四層和第五層)、路由元件(修改路由的全部寫法)

今日內容概要

  • 檢視元件
  • 路由元件

內容詳細

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等方法

第五層: 通過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()),
]

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方法

繼承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")