# Comparing Two Ways to Use “scope” in DRF Throttling: ScopedRateThrottle vs Inheriting UserRateThrottle When applying scope‑based throttling in DRF, two common patterns frequently appear. * **Pattern A**: Inherit from `UserRateThrottle` (or `SimpleRateThrottle`), create a custom class with a fixed `scope`, and attach it to the view via `throttle_classes`. * **Pattern B**: Register `ScopedRateThrottle` in `DEFAULT_THROTTLE_CLASSES` and simply set `throttle_scope = "login"` on the view. ## Do they produce the same effect? > **If you only need a single rate limit based on *user ID (or unauthenticated IP) + scope*, the outcomes are almost identical.** Differences arise in how the throttling is applied (error prevention), extensibility (multiple policies / custom criteria), and code structure (settings‑centric vs code‑centric). --- ## Commonality: Both build a key from *scope + (user ID or IP)* * `ScopedRateThrottle` constructs a key using `throttle_scope` (if present) plus the user ID or IP, then looks up the corresponding rate in `DEFAULT_THROTTLE_RATES`. * `UserRateThrottle` also limits by user ID for authenticated users and by IP for unauthenticated ones. To support multiple scopes, DRF recommends subclassing the throttle and assigning different `scope` values. --- ## Difference 1: Where the scope is declared – view attribute vs class attribute ### Pattern A: Scope fixed in the class ```python 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] ``` * The `scope` is **hard‑coded in the class**. * The view only needs to reference the class. * Reduces the chance of typos in the scope string across multiple views. ### Pattern B: Scope set on the view, interpreted by a shared throttle ```python 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" ``` * The `scope` lives **directly on the view**. * The shared `ScopedRateThrottle` checks the view for `throttle_scope` and applies the rate from settings. * Keeps code concise and centralizes policy management in settings. --- ## Difference 2: Who guarantees the application – global registration vs per‑view attachment ### Misconception about Pattern B Adding `ScopedRateThrottle` to `DEFAULT_THROTTLE_CLASSES` **does not** affect views that lack `throttle_scope`. So a global registration does not blanket‑block all APIs. ### Strength of Pattern A You can attach a throttle to **specific views** without touching global settings. This is handy when you cannot modify settings extensively or when you want to enforce throttling only on particular apps or endpoints. --- ## Difference 3: Extensibility – beyond a single limit The two patterns look similar only when each view has a single scope and a single rate. Beyond that, differences become pronounced. ### 1) Applying multiple throttles (burst + sustained) to one view DRF’s documentation shows using several `UserRateThrottle` subclasses for burst and sustained limits. ```python class Burst(UserRateThrottle): scope = "burst" class Sustained(UserRateThrottle): scope = "sustained" class SearchView(APIView): throttle_classes = [Burst, Sustained] ``` With `ScopedRateThrottle` alone, expressing two scopes for one view is awkward; you would need custom logic or additional classes. ### 2) Changing the basis of throttling `ScopedRateThrottle` operates on **user ID / IP** by default. Real‑world scenarios often require: * **IP + username** for login (to mitigate account‑targeted attacks) * **tenant_id** for multi‑tenant services * **API key** for key‑based limits These cases necessitate overriding `get_cache_key()` or similar logic, which naturally leads to **Pattern A** (subclassing / custom throttle). DRF also encourages custom throttles for such needs. --- ![Two keys opening an API connection](/media/editor_temp/6/e98f026a-a38e-43ca-8c86-fa7966dd3cdf.png) ## Which pattern should you choose? ### For most "view‑specific rate limits" → Pattern B (ScopedRateThrottle) * Minimal code changes * Central policy management via settings * No effect on views without `throttle_scope` ### If any of the following apply → Pattern A (inherit / custom class) * You need multiple limits (burst + sustained) on a single view * The throttling basis is not user ID / IP (e.g., username+IP, tenant, API key) * You cannot modify global settings and want to enforce throttling only on selected views * You prefer documenting the policy through the class name **Related article:** - [Mastering DRF Throttling: Settings, Application, and Custom Guides](/ko/whitedec/2026/1/26/drf-throttling-complete-guide/)