Throttling (ограничение количества запросов)

Как и в случае с permissions, троттлинг определяет, разрешить ли запрос к API. Отличие в том, что он устанавливает ограничение на лимит запросов и определяет разрешённую частоту обращений к API. Это нужно для того, чтобы контролировать нагрузку на сервер и отсекать клиентов, которые слишком часто отправляют запросы.
Можно установить лимит на количество запросов в секунду, минуту, час или день. Также можно определить несколько лимитов для одного клиента, например 1000 в день и 100 запросов в час. Можно создать ограничения на определенные действия, например, на загрузку фотографий на сервер.
При превышении лимита возвращается статус-код 429 "Too Many Requests". Если пользователь не аутентифицирован, то для идентификации пользователя запоминается ip-адрес, с которого приходят запросы.
Лимит запросов можно установить для всего проекта, можно — для конкретных view-функций, а можно скомбинировать оба эти подхода.
Распространённая практика — задать глобальные настройки для всего проекта, а затем уточнить их на уровне классов или функций.

Лимиты на уровне проекта

Чтобы глобально ограничить неаутентифицированных пользователей тысячей запросов в сутки, а аутентифицированным разрешить десять тысяч — в файле settings.py добавьте в словарь REST_FRAMEWORK параметры DEFAULT_THROTTLE_CLASSES иDEFAULT_THROTTLE_RATES:
Скопировать кодPYTHON
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.UserRateThrottle', 'rest_framework.throttling.AnonRateThrottle', ], 'DEFAULT_THROTTLE_RATES': { 'user': '10000/day', # лимит для UserRateThrottle 'anon': '1000/day', # лимит для AnonRateThrottle } }
Пользователь, который не прошел процедуру аутентифицикации, в Django называется анонимным, anonymous, сокращенно — Anon.
В параметре DEFAULT_THROTTLE_CLASSES мы регистрируем классы пользователей (User и Anon), а в DEFAULT_THROTTLE_RATES устанавливаем для них ограничения в формате количество_запросов/период_времени.
Количество запросов — это целое число, период времени указывается как second, minute, hour или day.
Имя user предустановлено в классе UserRateThrottle, а anon — в AnonRateThrottle

Лимиты на уровне view

Для того, чтобы изменить лимиты на уровне view-функций, есть декоратор @throttle_classes(): он принимает на вход классы из rest_framework.throttling.
Но если для глобальных настроек мы зарегистрировали эти классы в settings.py, то для лимитирования числа запросов на уровне view эти классы указывают там, где необходимо их подключить.
settings.py
Скопировать кодPYTHON
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ # не будем подключать классы глобально # подключим их только в тех view-классах, где надо установить лимиты ], 'DEFAULT_THROTTLE_RATES': { # но сами лимиты установим, и они будут доступны из всего кода проекта 'user': '10000/day', # лимит для UserRateThrottle 'anon': '1000/day', # лимит для AnonRateThrottle } }
views.py
Скопировать кодPYTHON
@api_view(['GET']) @throttle_classes([UserRateThrottle]) # здесь подключили класс UserRateThrottle # и для этого view-класса сработает лимит "10000/day" для залогиненных пользователей, # объявленный в settings.py def example_view(request): text = { 'hello': 'world' } return Response(text)
В случае с view-классами в тело класса добавляют поле throttle_classes:
Скопировать кодPYTHON
class ExampleView(APIView): # здесь подключили класс UserRateThrottle # и для этого view-класса сработает лимит "10000/day" для залогиненных пользователей, # объявленный в settings.py throttle_classes = [UserRateThrottle] def get(self, request): text = { 'hello': 'world' } return Response(text)
Чтобы создать свой лимит запросов (так называемый scope, «скоуп») для view-классов, подключите в settings.py класс ScopedRateThrottle и задайте лимит в DEFAULT_THROTTLE_RATES:
Скопировать кодPYTHON
REST_FRAMEWORK = { ... 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.ScopedRateThrottle', ], 'DEFAULT_THROTTLE_RATES': { ... # этот лимит сработает лишь в том view-классе, в котором он будет указан # имена (ключи) для scope указывает разработчик, в меру собственной фантазии 'low_request': '3/minute', }
Затем добавьте этот скоуп в тело класса:
Скопировать кодPYTHON
class ExampleView(APIView): throttle_scope = 'low_request'