python
40 lines · 8 steps
A login rate throttle in Django REST Framework
Limits login attempts per username-plus-IP and locks the pair out once the limit is hit.
Explained by
highlit
1from django.core.cache import cache
2from rest_framework.throttling import SimpleRateThrottle
3
4
5class LoginRateThrottle(SimpleRateThrottle):
6 scope = "login"
7
8 def get_cache_key(self, request, view):
9 username = (request.data.get("username") or "").strip().lower()
10 if not username:
11 return None
12 ident = self.get_ident(request)
13 return self.cache_format % {
14 "scope": self.scope,
15 "ident": f"{username}:{ident}",
16 }
17
18 def allow_request(self, request, view):
19 self.key = self.get_cache_key(request, view)
20 if self.key is None:
21 return True
22
23 if cache.get(f"{self.key}:locked"):
24 self.wait_time = cache.ttl(f"{self.key}:locked") or self.duration
25 return False
26
27 self.history = self.cache.get(self.key, [])
28 self.now = self.timer()
29 while self.history and self.history[-1] <= self.now - self.duration:
30 self.history.pop()
31
32 if len(self.history) >= self.num_requests:
33 cache.set(f"{self.key}:locked", True, timeout=self.duration)
34 self.wait_time = self.duration
35 return False
36
37 return self.throttle_success()
38
39 def wait(self):
40 return getattr(self, "wait_time", None) or super().wait()
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Keying a throttle on username-plus-IP targets brute-force attempts without blocking whole networks.
- 2A short-lived lock flag in the cache turns a soft rate limit into a hard cooldown once tripped.
- 3Returning None from the cache key cleanly opts a request out of throttling entirely.
Related explainers
python
import csv from collections import defaultdict from dataclasses import dataclass, field from decimal import Decimal, InvalidOperation
Aggregating CSV sales by category in Python
dataclasses
csv-parsing
defaultdict
Intermediate
8 steps
java
@Service public class ProductCatalogService { private final ProductRepository productRepository;
How Spring cache annotations keep data fresh
caching
cache-invalidation
dependency-injection
Intermediate
7 steps
typescript
import { CanActivate, ExecutionContext, Injectable,
A rate-limiting guard in NestJS
rate-limiting
guards
metadata
Intermediate
7 steps
python
from flask import Blueprint, jsonify, request, abort from .models import Article, db from .schemas import article_schema, articles_schema
Building a REST articles API with Flask Blueprints
rest-api
blueprints
serialization
Intermediate
7 steps
rust
use std::time::{Duration, Instant}; pub struct TokenBucket { capacity: f64,
A token bucket rate limiter in Rust
rate-limiting
token-bucket
lazy-refill
Intermediate
8 steps
python
import stripe from fastapi import APIRouter, Request, Header, HTTPException from app.config import settings
Handling Stripe webhooks in FastAPI
webhooks
signature-verification
event-routing
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-login-rate-throttle-in-django-rest-framework-explained-python-ec0c/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.