中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Django DRF路由與擴展功能是如何實現的

發布時間:2020-07-18 16:38:47 來源:億速云 閱讀:246 作者:小豬 欄目:開發技術

這篇文章主要講解了Django DRF路由與擴展功能是如何實現的,內容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。

一. 視圖集與路由的使用

使用視圖集ViewSet,可以將一系列邏輯相關的動作放到一個類中:

  • list() 提供一組數據
  • retrieve() 提供單個數據
  • create() 創建數據
  • update() 保存數據
  • destory() 刪除數據

ViewSet視圖集類不再實現get()、post()等方法,而是實現動作 action 如 list() 、create() 等。

視圖集只在使用as_view()方法的時候,才會將action動作與具體請求方式對應上。

1. 常用的視圖集父類

1.ViewSet

繼承自APIView 與 ViewSetMixin作用也與APIView基本類似,提供了身份認證、權限校驗、流量管理等。

ViewSet主要通過繼承ViewSetMixin來實現在調用as_view()時傳入字典(如{'get':'list'})的映射處理工作。

在ViewSet中,沒有提供任何動作action方法,需要我們自己實現action方法。

2.GenericViewSet

使用ViewSet通常并不方便,因為list、retrieve、create、update、destory等方法都需要自己編寫,而這些方法與前面講過的Mixin擴展類提供的方法同名,所以我們可以通過繼承Mixin擴展類來復用這些方法而無需自己編寫。但是Mixin擴展類依賴與GenericAPIView,所以還需要繼承GenericAPIView。

GenericViewSet就幫助我們完成了這樣的繼承工作,繼承自GenericAPIView與ViewSetMixin,在實現了調用as_view()時傳入字典(如{'get':'list'})的映射處理工作的同時,還提供了GenericAPIView提供的基礎方法,可以直接搭配Mixin擴展類使用。

3.ModelViewSet

繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

4.ReadOnlyModelViewSet

繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin。

下面我們還是通過案例,為大家演示吧!

首先,先創建一個子應用。

python3 manage.py startapp collect

5. 在collect下新建序列化器類

# collect下的serializers.py文件

from students.models import Student
from rest_framework import serializers


class StudentModelSerializer(serializers.ModelSerializer):

  class Meta:
    model = Student
    fields = ["id", "name", "age", "sex"]
    extra_kwargs = {
      "name": {"max_length": 10, "min_length": 4},
      "age": {"max_value": 150, "min_value": 0},
    }

  def validate_name(self, data):
    if data == "root":
      raise serializers.ValidationError("用戶名不能為root!")
    return data

  def validate(self, attrs):
    name = attrs.get('name')
    age = attrs.get('age')

    if name == "alex" and age == 22:
      raise serializers.ValidationError("alex在22時的故事。。。")

    return attrs


class StudentInfoModelSerializer(serializers.ModelSerializer):
  class Meta:
    model = Student
    fields = ["id", "name"]

6. collect下的urls.py

from django.urls import path, re_path
from collect import views

urlpatterns = [
  # 不要在同一個路由的as_view中書寫兩個同樣的鍵的http請求,會產生覆蓋!!!
  # ViewSet
  path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
  path('student1/get_5_girl/', views.Student1ViewSet.as_view({"get": "get_5_girl"})),
  re_path(r'^student1/(&#63;P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
  # GenericViewSet
  path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
  path('student2/get_5_girl/', views.Student3GenericViewSet.as_view({"get": "get_5_girl"})),
  # GenericViewSet,可以和模型類進行組合快速生成基本的API接口
  path("students3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
  # ModelViewSet 默認提供了5個API接口
  path("students4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
  re_path(r"^students4/(&#63;P<pk>\d+)/$", views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
  # ReadOnlyModelViewSet
  path("students5/", views.Student6ReadOnlyModelViewSet.as_view({"get": "list"})),
  re_path(r"^students5/(&#63;P<pk>\d+)/$", views.Student6ReadOnlyModelViewSet.as_view({"get": "retrieve"})),

  # 一個視圖類中調用多個序列化器
  path("student8/", views.Student8GenericAPIView.as_view()),

  # 一個視圖集中調用多個序列化器
  path("student9/", views.Student9ModelViewSet.as_view({"get": "list"})),
  re_path(r"^student9/(&#63;P<pk>\d+)/$", views.Student9ModelViewSet.as_view({"get": "retrieve"})),
]


"""
有了視圖集以后,視圖文件中多個視圖類可以合并成一個,但是,路由的代碼就變得復雜了,
需要我們經常在as_view方法 ,編寫http請求和視圖方法的對應關系,
事實上,在路由中,DRF也提供了一個路由類給我們對路由的代碼進行簡寫。
當然,這個路由類僅針對于 視圖集 才可以使用。
"""

# 路由類默認只會給視圖集中的基本5個API生成地址[ 獲取一條,獲取多條,添加.刪除,修改數據 ]
from rest_framework.routers import DefaultRouter
# 實例化路由類
router = DefaultRouter()
# router.register("訪問地址前綴","視圖集類","訪問別名")
# 注冊視圖視圖集類
router.register("student7", views.Student7ModelViewSet)

# 把路由列表注冊到django項目中
urlpatterns += router.urls

7. collect下的views.py

"""ViewSet視圖集,繼承于APIView,所以APIView有的功能,它都有,APIView沒有的功能,它也沒有"""
from rest_framework.viewsets import ViewSet
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response


class Student1ViewSet(ViewSet):
  def get_5(self, request):
    student_list = Student.objects.all()[:5]

    serializer = StudentModelSerializer(instance=student_list, many=True)

    return Response(serializer.data)

  def get_one(self, request, pk):
    student = Student.objects.get(pk=pk)

    serializer = StudentModelSerializer(instance=student)

    return Response(serializer.data)

  def get_5_girl(self, request):
    student_list = Student.objects.filter(sex=False)[:5]

    serializer = StudentModelSerializer(instance=student_list, many=True)

    return Response(serializer.data)


"""如果希望在視圖集中調用GenericAPIView的功能,則可以采用下面方式"""
from rest_framework.generics import GenericAPIView


class Student2ViewSet(ViewSet, GenericAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer

  def get_5(self, request):
    student_list = self.get_queryset()[:5]

    serializer = StudentModelSerializer(instance=student_list, many=True)

    return Response(serializer.data)

  def get_one(self, request, pk):
    student = self.get_object()

    serializer = StudentModelSerializer(instance=student)

    return Response(serializer.data)

  def get_5_girl(self, request):
    student_list = self.get_queryset().filter(sex=False)[:5]

    serializer = StudentModelSerializer(instance=student_list, many=True)

    return Response(serializer.data)

"""
上面的方式,雖然實現視圖集中調用GenericAPIView,但是我們要多了一些類的繼承。
所以我們可以直接繼承 GenericViewSet
"""
from rest_framework.viewsets import GenericViewSet


class Student3GenericViewSet(GenericViewSet):
  serializer_class = StudentModelSerializer
  queryset = Student.objects.all()

  def get_5(self, request):
    student_list = self.get_queryset()[:5]

    serializer = self.get_serializer(instance=student_list, many=True)

    return Response(serializer.data)

  def get_5_girl(self, request):
    student_list = self.get_queryset().filter(sex=False)[:5]

    serializer = self.get_serializer(instance=student_list, many=True)

    return Response(serializer.data)

"""
在使用GenericViewSet時,雖然已經提供了基本調用數據集(queryset)和序列化器屬性,但是我們要編寫一些基本的
API時,還是需要調用DRF提供的模型擴展類 [Mixins]
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin


class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer


from rest_framework.viewsets import ModelViewSet


class Student5ModelViewSet(ModelViewSet):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer


# 只讀模型視圖集
from rest_framework.viewsets import ReadOnlyModelViewSet


class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer


# 路由的使用
from rest_framework.decorators import action


class Student7ModelViewSet(ModelViewSet):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer

  # methods 指定允許哪些http請求訪問當前視圖方法
  # detail 指定生成的路由地址中是否要夾帶pk值,True為需要
  @action(methods=["GET"], detail=False)
  def get_6(self, request):
    serilizer = self.get_serializer(instance=self.get_queryset().get(pk=6))
    return Response(serilizer.data)


"""在多個視圖類合并成一個視圖類以后,那么有時候會出現一個類中需要調用多個序列化器"""

"""1. 在視圖類中調用多個序列化器"""
"""原來的視圖類中基本上一個視圖類只會調用一個序列化器,當然也有可能要調用多個序列化器"""
from .serializers import StudentInfoModelSerializer


class Student8GenericAPIView(GenericAPIView):
  queryset = Student.objects.all()

  # GenericAPI內部調用序列化器的方法,我們可以重寫這個方法來實現根據不同的需求來調用不同的序列化器
  def get_serializer_class(self):
    if self.request.method == "GET":
      # 2個字段
      return StudentInfoModelSerializer
    return StudentModelSerializer

  def get(self, request):
    """獲取所有數據的id和name"""
    student_list = self.get_queryset()

    serializer = self.get_serializer(instance=student_list, many=True)

    return Response(serializer.data)

  def post(self, request):
    """添加數據"""
    data = request.data
    serializer = self.get_serializer(data=data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data)


"""2. 在一個視圖集中調用多個序列化器"""

class Student9ModelViewSet(ModelViewSet):
  queryset = Student.objects.all()

  """要求:
      列表數據list,返回2個字段,
      詳情數據retrieve,返回所有字段,
  """
  def get_serializer_class(self):
    # 本次客戶端請求的視圖方法名 self.action
    if self.action == "list":
      return StudentInfoModelSerializer
    return StudentModelSerializer

二. 擴展功能

為了方便接下來的學習,我們創建一個新的子應用 opt

python3 manage.py startapp opt

因為接下來的功能中需要使用到登錄功能,所以我們使用django內置admin站點并創建一個管理員.

創建管理員以后,訪問admin站點,先修改站點的語言配置,在settings里修改

LANGUAGE_CODE = 'zh-hans'

1. 認證Authentication

可以在配置文件中配置全局默認的認證方案

REST_FRAMEWORK = {
  'DEFAULT_AUTHENTICATION_CLASSES': (
    'rest_framework.authentication.SessionAuthentication', # session認證
    'rest_framework.authentication.BasicAuthentication',  # 基本認證
  )
}

也可以在每個視圖中通過設置authentication_classess屬性來設置

opt下的urls.py

from django.urls import path
from opt import views

urlpatterns = [
  path('auth2/', views.Demo1APIView.as_view()),
  path('auth3/', views.Demo2APIView.as_view()),
]

opt下的views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

"""用戶的認證和權限識別"""


class Demo1APIView(APIView):
  """只允許登錄后的用戶訪問"""
  permission_classes = [IsAuthenticated]

  def get(self, request):
    """個人中心"""
    return Response("個人中心")


class Demo2APIView(APIView):
  """只允許管理員訪問"""
  permission_classes = [IsAdminUser]

  def get(self, request):
    """個人中心2"""
    return Response("個人中心2")

2. 權限Permissions

權限控制可以限制用戶對于視圖的訪問和對于具體數據對象的訪問。

  • 在執行視圖的dispatch()方法前,會先進行視圖訪問權限的判斷
  • 在通過get_object()獲取具體對象時,會進行模型對象訪問權限的判斷

內置提供的權限:

  • AllowAny 允許所有用戶
  • IsAuthenticated 僅通過認證的用戶
  • IsAdminUser 僅管理員用戶
  • IsAuthenticatedOrReadOnly 已經登陸認證的用戶可以對數據進行增刪改操作,沒有登陸認證的只能查看數據。

可以在配置文件中全局設置默認的權限管理類,如:

REST_FRAMEWORK = {
  ....
  
  'DEFAULT_PERMISSION_CLASSES': (
    'rest_framework.permissions.IsAuthenticated',
  )
}

如果未指明,則采用如下默認配置

'DEFAULT_PERMISSION_CLASSES': (
  'rest_framework.permissions.AllowAny',
)

也可以在具體的視圖中通過permission_classes屬性來設置。

opt下的urls.py

urlpatterns = [
  path('auth2/', views.Demo1APIView.as_view()),
  path('auth3/', views.Demo2APIView.as_view()),
  # 自定義權限
  path('auth4/', views.Demo3APIView.as_view()),
]

opt下的views.py

# 自定義權限
from rest_framework.permissions import BasePermission


class MyPermission(BasePermission):
  def has_permission(self, request, view):
    """
    針對訪問視圖進行權限判斷
    :param request: 本次操作的http請求對象
    :param view: 本次訪問路由對應的視圖對象
    :return:
    """
    if request.user.username == "xiaoming":
      return True
    return False


class Demo3APIView(APIView):
  permission_classes = [MyPermission]

  def get(self, request):
    """個人中心3"""
    return Response("個人中心3")

3. 限流Throttling

可以對接口訪問的頻次進行限制,以減輕服務器壓力。

一般用于付費購買次數,投票等場景使用.

可以在配置文件中,使用DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES進行全局配置

REST_FRAMEWORK = {
  # 限流
  'DEFAULT_THROTTLE_CLASSES': ( # 對全局進行設置
    'rest_framework.throttling.AnonRateThrottle',
    'rest_framework.throttling.UserRateThrottle'
  ),
  'DEFAULT_THROTTLE_RATES': {
    'anon': '3/hour',
    'user': '3/minute',
  }
}

DEFAULT_THROTTLE_RATES 可以使用 second, minute, hour 或day來指明周期。

也可以在具體視圖中通過throttle_classess屬性來配置

opt下的urls.py

urlpatterns = [
  path('auth2/', views.Demo1APIView.as_view()),
  path('auth3/', views.Demo2APIView.as_view()),
  # 自定義權限
  path('auth4/', views.Demo3APIView.as_view()),
  # 限流
  path('auth5/', views.Demo4APIView.as_view()),
]

opt下的views.py

# 限流
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle


class Demo4APIView(APIView):
  # throttle_classes = [UserRateThrottle, AnonRateThrottle] # 全局配置后,這里就不用指定

  def get(self, request):
    """投票頁面"""
    return Response("投票頁面")

4. 過濾Filtering

對于列表數據可能需要根據字段進行過濾,我們可以通過添加django-fitlter擴展來增強支持。

pip3 install django-filter

在配置文件里進行注冊

INSTALLED_APPS = [
  ...
  'django_filters', # 需要注冊應用,
]

REST_FRAMEWORK = {
  ...
  'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

在視圖中添加filter_fields屬性,指定可以過濾的字段。

opt下的urls.py

urlpatterns = [
  path('auth2/', views.Demo1APIView.as_view()),
  path('auth3/', views.Demo2APIView.as_view()),
  # 自定義權限
  path('auth4/', views.Demo3APIView.as_view()),
  # 限流
  path('auth5/', views.Demo4APIView.as_view()),
  # 過濾
  path('data5/', views.Demo5APIView.as_view()),
]

opt下的views.py

# 過濾
from rest_framework.generics import GenericAPIView, ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend


class Demo5APIView(ListAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer
  filter_backends = [DjangoFilterBackend] # 全局配置后,這里就不用指定了。
  filter_fields = ['age', "id"] # 聲明過濾字段

5. 排序Ordering

對于列表數據,REST framework提供了OrderingFilter過濾器來幫助我們快速指明數據按照指定字段進行排序。

使用方法:

在類視圖中設置filter_backends,使用rest_framework.filters.OrderingFilter過濾器,REST framework會在請求的查詢字符串參數中檢查是否包含了ordering參數,如果包含了ordering參數,則按照ordering參數指明的排序字段對數據集進行排序。

前端可以傳遞的ordering參數的可選字段值需要在ordering_fields中指明。

opt下的urs.py

urlpatterns = [
  path('auth2/', views.Demo1APIView.as_view()),
  path('auth3/', views.Demo2APIView.as_view()),
  # 自定義權限
  path('auth4/', views.Demo3APIView.as_view()),
  # 限流
  path('auth5/', views.Demo4APIView.as_view()),
  # 過濾
  path('data5/', views.Demo5APIView.as_view()),
  # 排序
  path('data6/', views.Demo6APIView.as_view()),
]

opt下的views.py

# 排序
from rest_framework.filters import OrderingFilter


class Demo6APIView(ListAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer
  filter_backends = [DjangoFilterBackend, OrderingFilter] # 局部配置會覆蓋全局配置
  filter_fields = ['id', "sex"]
  ordering_fields = ['id', "age"]

6. 分頁Pagination

REST framework提供了分頁的支持。

我們可以在配置文件中設置全局的分頁方式,如:

REST_FRAMEWORK = {
  'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
  'PAGE_SIZE': 100 # 每頁數目
}

也可通過自定義Pagination類,來為視圖添加不同分頁行為。在視圖中通過pagination_clas屬性來指明。

opt下的urls.py

urlpatterns = [
  path('auth2/', views.Demo1APIView.as_view()),
  path('auth3/', views.Demo2APIView.as_view()),
  # 自定義權限
  path('auth4/', views.Demo3APIView.as_view()),
  # 限流
  path('auth5/', views.Demo4APIView.as_view()),
  # 過濾
  path('data5/', views.Demo5APIView.as_view()),
  # 排序
  path('data6/', views.Demo6APIView.as_view()),
  # 分頁
  path('data7/', views.Demo7APIView.as_view()),
]

opt下的views.py

# 分頁
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

"""1. 自定義分頁器,定制分頁的相關配置"""
"""
# 頁碼分頁 PageNumberPagination
前端訪問形式:GET http://127.0.0.1:8000/opt/data7/&#63;page=4

page=1  limit 0,10
page=2  limit 10,20

# 偏移量分頁 LimitOffsetPagination
前端訪問形式:GET http://127.0.0.1:8000/opt/data7/&#63;start=4&size=3

start=0 limit 0,10
start=10 limit 10,10
start=20 limit 20,10
"""


class StandardPageNumberPagination(PageNumberPagination):
  """分頁相關配置"""
  page_query_param = "page"     # 設置分頁頁碼關鍵字名
  page_size = 3           # 設置每頁顯示數據條數
  page_size_query_param = "size"   # 設置指定每頁大小的關鍵字名
  max_page_size = 5         # 設置每頁顯示最大值


class StandardLimitOffsetPagination(LimitOffsetPagination):
  default_limit = 2         # 默認限制,默認值與PAGE_SIZE設置一致
  limit_query_param = "size"     # limit參數名
  offset_query_param = "start"    # offset參數名
  max_limit = 5           # 最大limit限制


class Demo7APIView(ListAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentModelSerializer
  # 分頁
  # 頁碼分頁類
  pagination_class = StandardPageNumberPagination
  # 偏移量分頁類
  # pagination_class = StandardLimitOffsetPagination

注意:如果在視圖內關閉分頁功能,只需在視圖內設置

pagination_class = None

看完上述內容,是不是對Django DRF路由與擴展功能是如何實現的有進一步的了解,如果還想學習更多內容,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

峨眉山市| 县级市| 修文县| 鄯善县| 义乌市| 四子王旗| 双鸭山市| 县级市| 安远县| 昭苏县| 连平县| 奇台县| 常宁市| 扶余县| 米脂县| 石景山区| 金阳县| 定州市| 江西省| 灵山县| 于田县| 雅江县| 永寿县| 阿克苏市| 林西县| 丰台区| 陵川县| 久治县| 五指山市| 红河县| 治县。| 射阳县| 即墨市| 北宁市| 蛟河市| 成都市| 景德镇市| 秦安县| 松溪县| 凉城县| 卫辉市|