- Classe de limitation de fréquence personnalisée
Pour créer votre propre classe de limitation, héritez de BaseThrottle et implémentez la méthode allow_request. Sinon, une erreur sera levée.
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
class CustomThrottle(SimpleRateThrottle):
scope = 'my_scope'
def get_cache_key(self, request, view):
# Utilise l'adresse IP comme clé de cache
return request.META.get('REMOTE_ADDR')
class UserThrottle(BaseThrottle):
dump = {} # Dictionnaire partagé pour stocker l'historique
def __init__(self):
self.history = None
def allow_request(self, request, view):
ip = request.META.get('REMOTE_ADDR')
import time
now = time.time()
if ip not in self.dump:
self.dump[ip] = [now]
return True
self.history = self.dump[ip]
# Supprime les entrées plus anciennes que 60 secondes
while self.history and now - self.history[-1] > 60:
self.history.pop()
if len(self.history) < 3: # Limite à 3 requêtes par minute
self.history.insert(0, now)
return True
return False
- Analyse du code source des fréquences
Le moteur de DRF utilise la méthode allow_request de la classe de limitation. Voici le foncsionnement de SimpleRateThrottle :
# SimpleRateThrottle (extrait du code source)
class SimpleRateThrottle(BaseThrottle):
cache = default_cache
timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s'
scope = None
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
def __init__(self):
# Lors de l'instanciation, self.rate est défini via get_rate()
if not getattr(self, 'rate', None):
self.rate = self.get_rate() # Retourne par ex. '3/m'
# num_requests et duration sont extraits de la chaîne
self.num_requests, self.duration = self.parse_rate(self.rate)
def get_rate(self):
# Récupère le taux depuis la configuration
return self.THROTTLE_RATES[self.scope]
def parse_rate(self, rate):
if rate is None:
return (None, None)
num, period = rate.split('/')
num_requests = int(num)
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
return (num_requests, duration)
def allow_request(self, request, view):
if self.rate is None:
return True
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
self.history = self.cache.get(self.key, [])
self.now = self.timer()
# Nettoie les entrées expirées
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()
# Résumé : Pour créer une classe de limitation personnalisée, il suffit d'hériter de SimpleRateThrottle,
# de redéfinir get_cache_key, de définir l'attribut scope et de configurer THROTTLE_RATES dans settings.
- Pagination
DRF propose trois types de pagination :
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class CustomPageNumberPagination(PageNumberPagination):
page_size = 2 # Éléments par page
page_query_param = 'page' # Paramètre de requête pour le numéro de page
page_size_query_param = 'size' # Paramètre optionnel pour définir la taille
max_page_size = 5 # Taille maximale autorisée
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3
limit_query_param = 'limit' # Nombre d'éléments affichés
offset_query_param = 'offset' # Index de départ
max_limit = 5
class CustomCursorPagination(CursorPagination):
cursor_query_param = 'cursor'
page_size = 2
ordering = '-id' # Tri par défaut (décroissant sur id)
- Tri et filtarge
Utilisez OrderingFilter pour le tri et SearchFilter pour la recherche textuelle :
from rest_framework.filters import OrderingFilter, SearchFilter
class MaVue(viewsets.ModelViewSet):
queryset = MonModele.objects.all()
serializer_class = MonSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['name'] # Champs sur lesquels faire une recherche
ordering_fields = ['id'] # Champs autorisés pour le tri
4.1 Filtrage avancé avec django‑filters
from django_filters.rest_framework.backends import DjangoFilterBackend
class MaVue(viewsets.ModelViewSet):
queryset = MonModele.objects.all()
serializer_class = MonSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['id'] # Champs sur lesquels filtrer exactement