<optgroup id="6y7f6"><small id="6y7f6"></small></optgroup>

<code id="6y7f6"></code>

  • <p id="6y7f6"><tbody id="6y7f6"><ins id="6y7f6"></ins></tbody></p>
    <code id="6y7f6"><form id="6y7f6"></form></code>

      【Django drf】視圖類APIView之五層封裝 ApiView的類屬性 drf配置文件

      ApiView的類屬性

      如下是ApiView所有的類屬性,我們抽取一部分進行介紹:
      可見這些類屬性,都是使用drf配置文件的默認配置。

      下列策略可以在全局設置 或者 在每一個視圖類中設置。
      允許依賴注入其他的設置文件, ApiView源碼的settings類屬性使測試更容易 (也就是不使用drf的api_settings)

      image-20230204162954141
      • renderer_classes: 用于設置視圖類的響應格式。默認情況會有兩種響應格式,一種是響應json字符串,一種是對瀏覽器的響應。
      • parser_classes:用于定義視圖類能夠解析的請求格式。默認情況下使用3個解析類進行解析,可以解析如下媒體類型:multipart/form-data,application/x-www-form-urlencoded,application/json
      • authentication_classes:認證類相關配置
      • throttle_classes:頻率類相關配置
      • permission_classes:權限類相關配置

      復習:

      # APIView跟之前的View區別
          -傳入到視圖方法中的是REST framework的Request對象,而不是Django的HttpRequeset對象;
          -視圖方法可以返回REST framework的Response對象-
          -任何APIException異常都會被捕獲到,并且處理成合適的響應信息;
          -在進行dispatch()分發前,會對請求進行身份認證、權限檢查、流量控制
      

      drf 配置文件之查找順序

      在apiView中使用了drf配置文件的默認配置。以下是配置的查找順序。

      方式三:查找順序(一般就用內置的即可)
           1. 視圖類  (局部配置)
           2. django settings  (全局配置) 
           3. drf api_settings (內置配置)
      說明:
      優先使用視圖類中renderer_classes的配置,其次使用django項目配置文件settings中的配置,最后使用drf內置的api_settings的配置
      
      

      在django的settings中應該按照如下格式寫:

      REST_FRAMEWORK = {
          'DEFAULT_RENDERER_CLASSES': [    # 配置響應
              'rest_framework.renderers.JSONRenderer',
              'rest_framework.renderers.TemplateHTMLRenderer',
          ],
          'DEFAULT_PARSER_CLASSES': [  # 配置請求
              'rest_framework.parsers.JSONParser',
              'rest_framework.parsers.FormParser',
              'rest_framework.parsers.MultiPartParser',
          ],
      }
      # 注意:所有配置都寫在一個REST_FRAMEWORK里面!
      

      drf之請求

      APIView之請求相關配置

      # 為什么需要進行請求相關配置?
      可以定制某些CBV只能只能接收json格式,不能接收其他格式。也就是為了自定義該接口可接受編碼格式。
      
      # 默認情況下
      前端上傳json                  request.data里面是   ---> python字典
      前端上傳urlencode\formdata    request.data里面是   ---> QueryDict
      
      
      # 方式一,在繼承自APIView及其子類的的視圖類中配置(局部配置)
      # 總共有三個:from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
      class BookView(APIView):
          parser_classes = [JSONParser,]
          
      # 方式二:在配置文件中配置(影響所有,全局配置)
          -django有套默認配置,每個項目有個配置
          -drf有套默認配置,每個項目也有個配置---》就在django的配置文件中
          REST_FRAMEWORK = {
          'DEFAULT_PARSER_CLASSES': [
              # 'rest_framework.parsers.JSONParser',
              'rest_framework.parsers.FormParser',
              # 'rest_framework.parsers.MultiPartParser',
          ],
      }
             
      # 方式三:全局配了1個,某個視圖類想要3個,怎么配?
          -只需要在視圖類,配置3個即可
          -因為:先從視圖類自身找,找不到,去項目的drf配置中找,再找不到,去drf默認的配置找
          
      # 視圖類方法中的request
          -data
          -__getattr__
          -query_params
      

      drf之響應

      APIView之響應相關配置

      # 為什么要在CBV中設置響應相關配置?
      因為對于drf的響應,如果使用瀏覽器和postman訪問同一個接口,Response返回的格式是不一樣的
      	-drf做了個判斷,如果是瀏覽器,好看一些,如果是postman只要json數據
          
          
      # 方式一:在視圖類中寫(局部配置)
      	-兩個響應類---》找---》drf的配置文件中找--》兩個類
          -from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
          class BookView(APIView):
          	renderer_classes=[JSONRenderer,]
      
      # 方式二:在項目配置文件中寫(全局配置)
          REST_FRAMEWORK = {
            'DEFAULT_RENDERER_CLASSES': [
              'rest_framework.renderers.JSONRenderer',
              'rest_framework.renderers.BrowsableAPIRenderer',
          ],
      }
          
      # 方式三:使用順序(一般就用內置的即可)
           1. renderer_classes
           2. django settings
           3. drf api_settings
      說明:
      優先使用視圖類中renderer_classes的配置,其次使用django項目配置文件settings中的配置,最后使用drf內置的api_settings的配置
      

      Response對象屬性

      # drf 的Response 源碼分析
          -from rest_framework.response import Response
          -視圖類的方法返回時,retrun Response ,走它的__init__, init中可以傳什么參數
          -Responses最終繼承httpresponse.
          
          
      # Response init可以傳的參數
          def __init__(self, 
                       data=None, 
                       status=None,
                       template_name=None, 
                       headers=None,
                       exception=False, 
                       content_type=None)
          
         -data:之前咱們寫的ser.data  可以是字典或列表,字符串---》序列化后返回給前端---》前端在響應體中看到的就是這個 
      
         -status: http響應的狀態碼,默認是200,你可以改
              -drf在status包下,把所有http響應狀態碼都寫了一遍,常量
              -from rest_framework.status import HTTP_200_OK
              -Response('dddd',status=status.HTTP_200_OK)
            
         -template_name:了解即可,修改響應模板的樣子,BrowsableAPIRenderer定死的樣子,后期公司可以自己定制
      
         -headers:響應頭,http響應的響應頭 示例:header={'xxx':'yyy'}
          
         -content_type :響應編碼格式,一般不動
         
      # 重點:data,status,headers
      
      # 原生djagno,如何在響應頭中加東西?
      
                 '''
                 四件套 render,redirect,HttpResponse,JsonResponse
                 方法: 產生HttpResponse然后添加屬性
                 '''
               # 示例:
                  obj = HttpResponse('dddd')
                  obj['xxc'] = 'yyc'
                  return obj
              
               響應頭添加屬性涉及知識 ---> 跨域 
      

      drf Response提供很多的狀態碼:
      image-20230203105225383

      在status內將所有狀態碼都寫了一遍:
      image-20230203105248081

      基于APIView + ModelSerializer寫五個接口

      視圖類

      from .models import Book
      from .serializer import BookSerializer
      
      
      class BookView(APIView):
          def get(self, request):
              books = Book.objects.all()
              ser = BookSerializer(instance=books, many=True)
              return Response(ser.data)
      
          def post(self, request):
              ser = BookSerializer(data=request.data)
              if ser.is_valid():
                  ser.save()
                  # 咱們現在只有ser序列化類的對象,但是咱們想要,新增的對象---》序列化成字典---》大前提,序列化類中的create方法一定要返回新增的對象
                  return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
              else:
                  return Response({'code': 101, 'msg': ser.errors})
      
      
      class BookDetailView(APIView):
          def get(self, request, pk):
              books = Book.objects.filter(pk=pk).first()
              ser = BookSerializer(instance=books)
              return Response(ser.data)
      
          def put(self, request, pk):
              books = Book.objects.filter(pk=pk).first()
              ser = BookSerializer(instance=books, data=request.data)
              if ser.is_valid():
                  ser.save()
                  return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
              else:
                  return Response({'code': 101, 'msg': ser.errors})
      
          def delete(self, request, pk):
              Book.objects.filter(pk=pk).delete()
              return Response({'code': 100, 'msg': '刪除成功'})
      

      序列化類

      ### ModelSerializer的使用
      class BookSerializer(serializers.ModelSerializer):
          # 跟表有關聯
          class Meta:
              model = Book
              fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
              extra_kwargs = {'name': {'max_length': 8},
                              'publish_detail': {'read_only': True},
                              'author_list': {'read_only': True},
                              'publish': {'write_only': True},
                              'authors': {'write_only': True},
                              }
      

      路由

      urlpatterns = [
          path('admin/', admin.site.urls),
          path('books/', views.BookView.as_view()),
          path('books/<int:pk>/', views.BookDetailView.as_view()),
      ]
      

      基于GenericAPIview 寫五個接口

      如果需要再新寫關于作者的五個接口 ----> 又需要寫一個CBV
      但是這兩個CBV的區別僅僅在于使用的 表模型序列化類 不同,其他都是重復的代碼。
      這豈不是很麻煩?能不能通過繼承的方式,優化代碼?
      于是就寫了一個 GenericAPIview --繼承于--> APIView ,以后可以基于這個類來寫5個接口。

      GenericAPIview必備設置

      image-20230203114428183

      如果你想使用GenericAPIview,你需要從如下二種選擇其一:

      1. 在視圖類中設置如下屬性 (常用)

        queryset、serializer_class

      2. 重寫GenericAPIview類的get_queryset()/get_serializer_class()方法

      如果你重寫了一個視圖方法,那么重要的是 你應該調用get_queryset() 而不是直接的訪問queryset屬性。
      因為queryset將只被設置一次,并且為了后續到來的所有請求,這個結果會被緩存。

      總而言之,不要直接訪問queryset、serializer_class屬性,而是使用GenericAPIview提供的各種方法獲取。

      查詢所有

      image-20230204145645336

      # 首先指定模型對象 和 序列化類
      class BookView(GenericAPIView):
          queryset = Book.objects.all()
          # queryset = Book.objects 這樣也是可行的
          serializer_class = BookSerializer
      
      # 以下代碼都是等效的
      objs = Book.objects.all()
      objs = self.get_queryset()
      
      # 以下代碼都是等效的
      ser = self.get_serializer(instance=objs, many=True)
      BookSerializer(instance=objs, many=True)
      

      get_queryset()

      image-20230203173342133

      get_queryset方法得到視圖中的列表對象!
      這個列表對象必須是一個可迭代的,也可以是一個queryset對象。

      默認使用self.queryset來獲取(視圖中的列表對象):

      image-20230203202821381

      應該總是使用這個方法來獲取,而不是直接調用self.queryset。

      get_queryset源碼做了些什么事?

      1. 如果沒有在視圖類中寫queryset屬性,然后就調用get_queryset,會拋出異常。
      2. 獲取我們設置的queryset屬性,如果是Queryset對象,則調用all()方法,最后將我們設置的queryset類屬性返回出去。

      get_serializer()

      image-20230203201429473

      使用get_serializer()方法可以返回序列化器的實例,此序列化器,被應用于校驗、反序列化前端輸入和序列化后端輸出。

      get_serializer源碼做了些什么事?

      1. 通過get_serializer_class方法獲取了我們在視圖類中指定的序列化類

      2. 添加了一個'context'參數傳入我們的序列化類。

        相當于BookSerializer(instance=objs, many=True, context={一些數據...})

      image-20230203202858354

      get_serializer_class()

      get_serializer_class方法基本上什么事情都沒有做,直接將序列化器返回,有需求可以重寫get_serializer_class。
      可以實現:不同的接口使用的序列化類不一樣。序列化使用某一個序列化類,反序列化用另一個序列化類。

      image-20230203203043304

      重寫:

      image-20230203224942685

      查詢一個

      image-20230203212916443

      這里會根據傳入的pk參數查詢出對應的模型對象,
      正常情況下寫查詢一個的接口我們需要手動寫orm( 比如Book.objects.filter(pk=pk)),根據主鍵將對象查出來。
      這里因為使用了GenericAPIview,他會自動幫我們查。

      get_object()

      就是通過pk參數和get_object方法將模型對象查詢出來的。

      返回應用于詳細視圖的對象實例。默認使用 lookup_field 參數過濾基本的查詢集。
      該方法可以被重寫以提供更復雜的行為,例如基于多個 URL 參數的對象查找。

      lookup_field屬性

      image-20230203202258635

      如果你想使用pk之外的對象查找方式,可以設置lookup_field。如果有更復雜的查找需求,可以重寫get_object()。

      以下給出一個示例:
      image-20230203214531929

      修改查詢條件為書籍的名字:

      image-20230203214630826

      filter_queryset()

      image-20230204141418521

      可見在get_object方法中,調用了get_queryset()獲取了我們放在視圖中的queryset,然后使用了filter_queryset()對我們從數據庫中獲取的queryset進行了過濾操作。

      image-20230204142438060

      關于filter_queryset的解釋是:
      給他一個queryset,他會使用任何一個你正在使用的后端過濾器,進行過濾。

      self.filter_backends:由于我們類中沒有配置,所以會指向GenericAPIview類中的filter_backends。

      在GenericAPIview類中默認使用的是drf配置文件中指定的默認過濾器。
      image-20230204143250366

      然后drf配置文件中,默認是不過濾:
      image-20230204143605380

      所有總而言之,默認就是不過濾,但是我們可以通過在自己的視圖類中寫filter_backends屬性,來指定過濾器。

      新增一個

          def post(self, request):
              ser = self.get_serializer(data=request.data)
              if ser.is_valid():
                  ser.save()
                  return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
              else:
                  return Response({'code': 101, 'msg': ser.errors})
      

      修改一個

       def put(self, request, pk):
              obj = self.get_object()
              ser = self.get_serializer(instance=obj, data=request.data)
              if ser.is_valid():
                  ser.save()
                  return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
              else:
                  return Response({'code': 101, 'msg': ser.errors})
      

      刪除一個

        def delete(self, request, pk):
              obj = self.get_object()
              obj.delete()
              return Response({'code': 100, 'msg': '刪除成功'})
      

      更多GenericAPIview 類屬性

      基本設置

      • queryset - 用于從視圖返回對象的查詢結果集。通常,你必須設置此屬性或者重寫 get_queryset() 方法。如果你重寫了一個視圖的方法,重要的是你應該調用 get_queryset() 方法而不是直接訪問該屬性,因為 queryset 將被計算一次,這些結果將為后續請求緩存起來。
      • serializer_class - 用于驗證和反序列化輸入以及用于序列化輸出的Serializer類。 通常,你必須設置此屬性或者重寫get_serializer_class() 方法。
      • lookup_field - 用于執行各個model實例的對象查找的model字段。默認為 'pk'。 請注意,在使用超鏈接API時,如果需要使用自定義的值,你需要確保在API視圖序列化類設置查找字段。
      • lookup_url_kwarg - 應用于對象查找的URL關鍵字參數。它的 URL conf 應該包括一個與這個值相對應的關鍵字參數。如果取消設置,默認情況下使用與 lookup_field相同的值。

      配置文件相關

      以下屬性用于在與列表視圖一起使用時控制分頁。

      • pagination_class - 當分頁列出結果時應使用的分頁類。默認值與 DEFAULT_PAGINATION_CLASS 設置的值相同,即 'rest_framework.pagination.PageNumberPagination'。

      • filter_backends - 用于過濾查詢集的過濾器后端類的列表。默認值與DEFAULT_FILTER_BACKENDS 設置的值相同。

      基于GenericAPIView + 5個視圖擴展類寫五個接口

      雖然使用了GenericAPIview類寫五個接口,但是寫的代碼還是太多了,并沒有減少代碼呀!
      CBV類中的方法 get、post、put、delete代碼都是重復的,是不是可以再進行優化?

      drf的作者自然想到了這一點,他提供了5個視圖擴展類,幫我們寫了這一部分代碼!
      先導入五個視圖擴展類:

      from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin
      

      查詢所有

      class BookView(GenericAPIView, ListModelMixin):
          queryset = Book.objects
          serializer_class = BookSerializer
      
          def get(self, request):
              return self.list(request)
      

      現在就只需要使用self.list調用ListModeMixin類中寫的代碼:
      image-20230204151025047

      和我們之前寫的差不多,先獲取queryset然后將其傳入序列化類。中間還進行了過濾,分頁操作。

      查詢一個

      class BookDetailView(GenericAPIView, RetrieveModelMixin):
          queryset = Book.objects
          serializer_class = BookSerializer
      
          def get(self, request, pk):  # 注意要傳入這個pk
              return self.retrieve(request)
      

      對應關系

      這樣很方便的就可以實現五個接口,我們只需要知道方法直接的對應關系就行了:

      ListModelMixin      -->  list      -->  查詢所有
      RetrieveModelMixin  -->  retrieve  -->  查詢一個
      CreateModelMixin    -->  create    -->  新增一個
      UpdateModelMixin    -->  update    -->  修改一個
      DestroyModelMixin   -->  destroy   -->  刪除一個
      

      代碼:

      class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
          queryset = Book.objects
          serializer_class = BookSerializer
      
          def get(self, request):
              return self.list(request)
      
          def post(self, request):
              return self.create(request)
      
      class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
          queryset = Book.objects
          serializer_class = BookSerializer
      
          def get(self, request, pk):
              return self.retrieve(request)
      
          def put(self, request, pk):
              return self.update(request)
      
          def delete(self, request, pk):
              return self.destroy(request)
      

      雖然已經簡化了代碼,但是其實還是有重復的部分比如這些請求方法,之后還會進行封裝。

      繼承具體視圖類寫五個接口

      什么叫具體視圖類?Concrete View Classes
      也就是drf作者已經幫你把CBV需要寫的接口代碼都寫好了,打包成了一個個類,你只需要直接繼承這些類,你的視圖類就會有相應的接口,是不是很神奇 ~ ~

      drf提供如下具體視圖類:

      image-20230204154227345

      注意:沒有DestroyUpdateAPIView

      直接上代碼:

      from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
      
      
      class BookView(ListCreateAPIView):  # 查詢所有 新增一個 
          queryset = Book.objects
          serializer_class = BookSerializer
      
      
      class BookDetailView(RetrieveUpdateDestroyAPIView):   # 查詢一個 修改一個 刪除一個
          queryset = Book.objects
          serializer_class = BookSerializer
          
      

      使用ModelViewSet寫五個接口

      之前我們使用兩個CBV寫五個接口的原因是:
      查詢一個和查詢所有都是使用get請求,為了解耦合,避免在類中的get方法中寫太多代碼,所以將其拆成兩個CBV。

      而使用ModelViewSet可以實現,一個視圖類寫5個接口。

      from rest_framework.viewsets import ModelViewSet
      
      class BookView(ModelViewSet):
          queryset = Book.objects
          serializer_class = BookSerializer
      

      參考

      posted @ 2023-02-04 18:34  passion2021  閱讀(99)  評論(0編輯  收藏  舉報
      欧洲黄色网页链接入口,免费A级毛片无码无遮挡久久影院,a免费黄色网址,国产一级黄色的网站
      <optgroup id="6y7f6"><small id="6y7f6"></small></optgroup>

      <code id="6y7f6"></code>

    1. <p id="6y7f6"><tbody id="6y7f6"><ins id="6y7f6"></ins></tbody></p>
      <code id="6y7f6"><form id="6y7f6"></form></code>