DRF Throttlingで「scope」を使う2つの手法比較:ScopedRateThrottle vs UserRateThrottleの継承
DRFでscopeベースのスロットリングを設定する際、よく使われる2つのパターンがあります。
- 手法A:
UserRateThrottle(またはSimpleRateThrottle)を継承し、scopeを埋め込んだカスタムクラスを作成して、ビューにthrottle_classesで直接付与します。 - 手法B:
DEFAULT_THROTTLE_CLASSESにScopedRateThrottleを登録し、ビューにはthrottle_scope = "login"だけを書きます。
「結局同じ効果では?」という疑問に答えると、次のとおりです。
単一の速度制限を「ユーザーID(または未認証IP)+ scope」で設定する場合、結果はほぼ同じです。 ただし 適用方法(ミス防止)、拡張性(複数ポリシー/カスタム基準)、コード構造(設定中心 vs コード中心)で差が生じ、選択基準が決まります。
共通点:両方とも「scope + (user id or IP)」でキーを作成します
ScopedRateThrottleはビューにthrottle_scopeがある場合、scope+ ユーザーID/IP でキーを構成し、DEFAULT_THROTTLE_RATESから該当スコープのレートを取得して適用します。UserRateThrottleも基本的に認証ユーザーは user id、未認証は IP を基準に制限し、複数を使う場合はクラスを継承してscopeを変える形をDRFが公式例として示します。
差異1) 「scopeをどこに書くか」:ビュー属性 vs クラス属性
手法A:クラスにscopeを固定(明示的)
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class CustomDomainSaveThrottle(UserRateThrottle):
scope = "custom_domain_save"
class SaveCustomDomainView(APIView):
throttle_classes = [CustomDomainSaveThrottle]
- scopeはクラスに固定されます。
- ビューは「このクラスを使う」だけで完了。
- ビューごとにscope文字列をタイプミスするリスクが減ります(クラス名が実質的にドキュメントになります)。
手法B:ビューにscopeだけを書き、共通throttleが解釈(設定中心)
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.ScopedRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {
"login": "5/min",
}
}
from rest_framework.views import APIView
class LoginView(APIView):
throttle_scope = "login"
- scopeはビューに直接書きます。
- 共通throttle(
ScopedRateThrottle)が「このビューはloginスコープ?」と判断し、設定からrateを取得して適用します。 - コードが短く、settingsでポリシーを一目で管理しやすいです。
差異2) 「適用を誰が保証するか」:基本登録 vs ビュー別装着
手法Bのポイント(誤解が多い)
DEFAULT_THROTTLE_CLASSESにScopedRateThrottleを入れても、throttle_scopeが設定されていないビューには適用されません。
つまり「全体設定に入れたら全APIがブロックされる?」という心配は通常不要です。
逆に手法Aの強み
全体設定を触らずに、特定ビューにだけ望むthrottleを「装着」できます。 (チーム/サービス構成上settingsを大きく変更できない場合や、特定アプリ/エンドポイントだけ強制したいときに便利)。
差異3) 拡張性:単一制限を超えるとAが有利になる
見た目はほぼ同じに見えるのは「1ビューに1scope、1速度制限」までです。 その後は差が出ます。
1) 「バースト + 持続」など 複数throttle を1ビューに掛けたい場合
DRFドキュメントでも複数UserRateThrottleを同時に使うパターン(バースト/サステイン)を例示しています。
class Burst(UserRateThrottle):
scope = "burst"
class Sustained(UserRateThrottle):
scope = "sustained"
class SearchView(APIView):
throttle_classes = [Burst, Sustained]
ScopedRateThrottleだけでは「1ビューにscopeを2つ」自然に表現しにくく、結局 クラスが必要 になります(またはカスタム実装)。
2) 「誰を基準に制限するか」が変わる瞬間
ScopedRateThrottleはデフォルトで user id / IP 軸で動きます。
しかし実務ではこうした要件がすぐに出てきます。
- ログイン:IP + usernameの組み合わせで制限したい(アカウントターゲット攻撃対策)
- 組織/テナント:tenant_idでまとめて制限したい
- API Key:キー単位で制限したい
この場合は結局、get_cache_key()などのロジックをカスタマイズする必要があり、手法A(継承/カスタムクラス) へ自然に移行します(DRFでもカスタムthrottleを推奨する場面です)。

それで何を使えばいい?
ほとんどの「ビュー別レートリミット」なら → 手法B(ScopedRateThrottle)推奨
- コード最小化
- settingsでポリシー一括管理
- ビューには
throttle_scopeだけ書けば完了 - scopeのないビューには適用されない
以下のいずれかに該当するなら → 手法A(継承/カスタムクラス)推奨
- 1ビューにバースト+持続など複数制限を同時に掛けたい
- 「user/IP」ではなくカスタム基準(username+IP、tenant、API key等)が必要
- 全体設定を触れにくく、特定ビューにだけ強制装着したい
- クラス名でポリシーを「ドキュメント化」したい(読む人が意図をすぐ把握)
関連記事: