1. 程式人生 > >DRF Django REST framework 之 頻率,響應器與分頁器元件(六)

DRF Django REST framework 之 頻率,響應器與分頁器元件(六)

頻率元件

頻率元件類似於許可權元件,它判斷是否給予請求通過。頻率指示臨時狀態,並用於控制客戶端可以向API發出的請求的速率。

與許可權一樣,可以使用多個調節器。API可能會對未經身份驗證的請求進行限制,而對於經過身份驗證的請求則進行限制較少。

例如,可以將使用者限制為每分鐘最多60個請求,每天最多1000個請求。

自定義頻率元件

使用方式與許可權,認證元件幾乎相同

該方式沒有DRF提供的方式簡潔

import time
import math

from rest_framework import exceptions


class MyException(exceptions.Throttled):
    default_detail = '連線次數過多'
    extra_detail_plural = extra_detail_singular = '請在{wait}秒內訪問'

    def __init__(self, wait=None, detail=None, code=None):
        super().__init__(wait=wait, detail=detail, code=code)


class VisitThrottle():
    user_visit_information = dict()
    visited_times = 1
    period = 60
    allow_times_per_minute = 5
    first_time_visit = True

    def allow_request(self, request, view):
        self.request_host = request_host = request.META.get("REMOTE_ADDR")
        current_user_info = self.user_visit_information.get(request_host, None)

        if not self.__class__.first_time_visit:
            self.user_visit_information[request_host][0] += 1
            current_visit_times = self.user_visit_information[request_host][0]

            if current_visit_times > self.allow_times_per_minute:
                if self._current_time - current_user_info[1] <= self.period:
                    if len(current_user_info) > 2:
                        current_user_info[2] = self._time_left
                    else:
                        current_user_info.append(self._time_left)

                    view.throttled = self.throttled
                    return None
                else:
                    self.__class__.first_time_visit = True

        if self.first_time_visit:
            self.__class__.first_time_visit = False
            self._initial_infomation()

        return True

    def wait(self):
        return self.period - self.user_visit_information[self.request_host][2]

    def throttled(self, request, wait):
        raise MyException(wait=wait)

    @property
    def _current_time(self):
        return time.time()

    @property
    def _time_left(self):
        return math.floor(self._current_time - self.user_visit_information.get(self.request_host)[1])

    def _initial_infomation(self):
        self.user_visit_information[self.request_host] = [self.visited_times, self._current_time]

基於每個檢視設定頻率:

class BookView(ModelViewSet):# 指定頻率類,固定寫法
    throttle_classes = [RateThrottle]
    # 獲取資料來源, 固定寫法
    queryset = models.Book.objects.all()
    # 序列化類, 固定寫法
    serializer_class = BookSerializer

使用DRF簡單頻率控制(區域性)

from rest_framework.throttling import SimpleRateThrottle


class RateThrottle(SimpleRateThrottle):
    # 每分鐘最多五次
    rate = '5/m'

    def get_cache_key(self, request, view):
        return self.get_ident(request)

rate代表訪問評率,上面表示每分鐘五次, get_cache_key 是必須存在的,它的返回值告訴當前頻率控制組件要使用什麼方式區分訪問者(比如ip地址)。

在檢視中使用:

class BookView(ModelViewSet):
    # 指定頻率類,固定寫法
    throttle_classes = [RateThrottle]
    # 獲取資料來源, 固定寫法
    queryset = models.Book.objects.all()
    # 序列化類, 固定寫法
    serializer_class = BookSerializer

全域性頻率控制

首先定義一個頻率控制類,並且必須繼承 SimpleRateThrottle 這個類,它是DRF提供的一個方便的頻率控制類,請看下面的程式碼:

from rest_framework.throttling import SimpleRateThrottle


class RateThrottle(SimpleRateThrottle):
    scope = "visit_rate"

    def get_cache_key(self, request, view):
        return self.get_ident(request)

在全域性配置頻率控制引數:

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES": ('app.utils.throttles.RateThrottle',),
    "DEFAULT_THROTTLE_RATES": {
        "visit_rate": "5/m"
    }
}

這樣就實現了,每分鐘最多五次訪問的邏輯。

 

另外,可以使用 DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES 設定全域性設定預設的限制策略。

例如:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        # 遊客每天訪問次數不能超過100次
        'anon': '100/day',
        # 使用者每天訪問次數不能超過1000次
        'user': '1000/day'
    }
}

響應器

在使用DRF的Response類來將資料響應給客戶端時,不管是POSTMAN工具還是瀏覽器,都能瀏覽到經過格式化後的,清晰易懂資料,DRF是怎麼做的呢?其實就是通過響應器元件

響應器元件的使用

如果不需要使用DRF提供給瀏覽器的格式化後的資料,只需要禁止該響應方式即可:

from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer

class BookView(ModelViewSet):
    # 指定響應器類,固定寫法,返回json格式資料
    renderer_classes = [JSONRenderer]
    # 獲取資料來源, 固定寫法
    queryset = models.Book.objects.all()
    # 序列化類, 固定寫法
    serializer_class = BookSerializer

這樣,瀏覽器再次訪問,接收到的就是普通的json格式資料,而不是經過DRF格式化後的資料,renderer_classes的查詢邏輯與之前的解析器等等元件是完全一樣的。

分頁器

為了伺服器效能考慮,也為了使用者體驗,我們不應該一次將所有的資料從資料庫中查詢出來,返回給客戶端瀏覽器,如果資料量非常大,這對於伺服器來講,可以說是效能災難,而對於使用者來講,載入速度將會非常慢。

而分頁器能很好的解決該問題。

分頁器的使用

第一步:匯入模組

from rest_framework.pagination import PageNumberPagination

第二步:獲取資料

books = Book.objects.all()

第三步:建立分頁器

paginater = PageNumberPagination()

第四步:開始分頁

paged_books = paginater.paginate_queryset(books, request)

第五步:將分頁後的資料進行序列化

serialized_data = BookSerializer(paged_books, many=True)

第六步:返回資料

return Response(serialized_data.data)

常用引數介紹

常用分頁器引數:
1. page_size:        用來控制每頁顯示多少條資料(全域性引數名為PAGE_SIZE);
2. page_query_param:    用來提供直接訪問某頁的資料;
3. page_size_query_param: 臨時調整當前顯示多少條資料
4. max_page_size:       控制page_size_query_param引數能調整的最大條數

偏移分頁器引數
1. default_limit:      每頁顯示的資料條數 
2. offset_query_param:   要偏移的標杆,在前端以get的形式傳,key為offset('可修改') 
3. limit_query_param:   偏移量,在前端以get的形式傳,key為limit('可修改') 
4. max_limit:         一頁最大的顯示條數

自定義分頁器

常用分頁器 url :

# url:示例
http://http://127.0.0.1:8000/books/?page=2
# 在第二頁顯示,100條,但是page_size最大不能超過定義的max_page_size
http://http://127.0.0.1:8000/books/?page=2&page_size=100

常用分頁器類:

from rest_framework.pagination import PageNumberPagination


# 定義分頁器類
class BookPageNumberPagination(PageNumberPagination):
    # 預設一頁條數
    page_size = 2
    # 前端傳送的頁數關鍵字名
    page_query_param = 'page'
    # 使用者自定義一頁條數 關鍵字名
    page_size_query_param = 'page_size'
    # 使用者自定義一頁最大控制條數
    max_page_size = 2

偏移分頁器 url :

# url:示例
http://http://127.0.0.1:8000/books/?limit=10
# 在100條後顯示10條, 但是顯示的條數不能超過定義的max_limit
http://http://127.0.0.1:8000/books/?limit=10&offset=100

偏移分頁器類:

from rest_framework.pagination import LimitOffsetPagination


class BookLimitOffsetPagination(LimitOffsetPagination):
    # 預設一頁條數
    default_limit = 2
    # 從offset開始往後顯示limit條
    limit_query_param = 'limit'
    offset_query_param = 'offset'
    # 最大顯示多少條
    max_limit = 4

檢視類使用:

class BookView(ModelViewSet):
    # 指定分頁器類,固定寫法,只能指定一個分頁器類
    pagination_class = BookPageNumberPagination
    # pagination_class = BookLimitOffsetPagination
    # 獲取資料來源, 固定寫法
    queryset = models.Book.objects.all()
    # 序列化類, 固定寫法
    serializer_class = BookSerializer

~>.&