DRF三大认证、过滤排序、分页笔记
执行顺序:APIView的
dispatch()→initial()方法内部依次执行 认证 → 权限 → 频率,在视图get/post方法执行之前运行。
一、APIView的dispatch源码流程(底层原理)
def dispatch(self, request, *args, **kwargs):
# 1.封装生成新的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
try:
# 【核心】三大认证在这里执行
self.initial(request, *args, **kwargs)
# self.perform_authentication(request) # 认证
# self.check_permissions(request) # 权限
# self.check_throttles(request) # 频率
# 反射:根据请求方式(get/post)找到视图类对应的方法
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
response = handler(request, *args, **kwargs)
except Exception as exc:
# 全局异常捕获,统一处理返回
response = self.handle_exception(exc)
return self.finalize_response(request, response, *args, **kwargs)
重要结论
- 继承
APIView后,request被重新封装,视图内可以使用self.request - 视图方法执行前,先跑认证、权限、频率校验
- 整个过程抛出的异常都会被DRF捕获处理
- APIView自动关闭CSRF校验
1、认证 Authentication(判断用户是否登录)
作用:接口需要登录之后才可以访问。token登录方案。
流程
- 登录接口:用户名密码校验,生成token,存入数据库中间表
UserToken - 访问需要登录的接口:请求头携带
token - 自定义认证类读取请求头token,去数据库校验
- 校验成功返回
(user对象, token);失败抛AuthenticationFailed异常
①登录接口示例(ViewSet + @action)
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from rest_framework.response import Response
import uuid
from .models import User, UserToken
class UserView(ViewSet):
@action(methods=["POST"], detail=False)
def login(self, request):
username = request.data.get("username")
password = request.data.get("password")
user = User.objects.filter(username=username, password=password).first()
if user:
token_str = str(uuid.uuid4())
# 有就更新,没有就新增
UserToken.objects.update_or_create(user=user, defaults={"token": token_str})
return Response({"code":100, "msg":"登录成功", "token":token_str})
return Response({"code":101, "msg":"用户名或密码错误"})
②自定义认证类
继承 BaseAuthentication,重写authenticate方法
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken
class LoginAuthentication(BaseAuthentication):
def authenticate(self, request):
# 从请求头拿token,请求头key:Token → META中变成 HTTP_TOKEN
token = request.META.get("HTTP_TOKEN")
user_token = UserToken.objects.filter(token=token).first()
if user_token:
# 返回 (用户对象, token),后续视图可以通过 request.user 获取登录用户
return user_token.user, token
raise AuthenticationFailed("请登录后操作")
③使用认证类(3种写法)
- 局部视图使用(只当前视图生效)
class BookView(CreateAPIView):
authentication_classes = [LoginAuthentication]
- 全局配置(settings.py) 所有视图默认生效
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"app.auth.LoginAuthentication"
]
}
- 局部禁用(比如登录接口不需要登录)
authentication_classes = []
查找优先级:视图类局部 > settings全局 > drf内置
2、权限 Permissions(已经登录,判断用户有没有操作资格)
场景:普通用户可以查,只有超级管理员才能新增/修改数据
使用步骤
- 继承
BasePermission - 重写
has_permission(self, request, view) - 有权限返回
True;没有权限返回False;可以设置self.message自定义错误提示
from rest_framework.permissions import BasePermission
class SuperPermission(BasePermission):
def has_permission(self, request, view):
# request.user 就是认证类返回的登录用户
if request.user.user_type == 3:
return True
self.message = "您不是超级用户,无法操作"
return False
使用方式
- 局部配置
class BookView(CreateAPIView):
permission_classes = [SuperPermission]
- 全局配置 settings.py
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
"app.permission.SuperPermission"
]
}
- 局部禁用
permission_classes = []
3、频率 Throttling(限流,限制访问次数,防刷接口)
根据IP / 用户id /设备id限制一段时间内访问次数
使用步骤
- 继承
SimpleRateThrottle - 设置类属性
rate = '3/m'→ 每分钟最多3次-
s秒,m分钟,h小时,d天
-
- 重写
get_cache_key,返回用来做限制的标识(ip、用户id)
from rest_framework.throttling import SimpleRateThrottle
class CommonThrottle(SimpleRateThrottle):
rate = "3/m" # 一分钟最多访问3次
def get_cache_key(self, request, view):
# 根据客户端IP限流(不需要登录)
return request.META.get("REMOTE_ADDR")
# 如果登录用户,按用户id限流
# return request.user.id
使用
#局部
throttle_classes = [CommonThrottle]
#全局 settings.py
REST_FRAMEWORK={
"DEFAULT_THROTTLE_CLASSES":["app.throttle.CommonThrottle"]
}
#局部禁用
throttle_classes = []
底层使用Django缓存保存访问记录。
4、过滤与排序(只针对查询列表接口 ListAPIView / ModelViewSet的list)
需要继承
GenericAPIView的视图才支持filter_backends
4.1 排序 OrderingFilter
from rest_framework.filters import OrderingFilter
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter]
ordering_fields = ["price", "id"] # 允许排序的字段
访问地址:
-
?ordering=price升序 -
?ordering=-price降序 -
?ordering=price,-id多字段排序
4.2 搜索(drf内置SearchFilter,模糊匹配)
from rest_framework.filters import SearchFilter
filter_backends = [OrderingFilter, SearchFilter]
search_fields = ["name"]
请求:?search=红楼梦
4.3 第三方精确过滤 django‑filter
- 安装
pip install django-filter,注册app
from django_filters.rest_framework.backends import DjangoFilterBackend
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "publish"]
请求:?name=红楼梦&publish=北京出版社
4.4 自定义过滤类(最灵活,可以写Q复杂查询)
继承BaseFilterBackend,重写filter_queryset
from rest_framework.filters import BaseFilterBackend
from django.db.models import Q
class CommonFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
name = request.query_params.get("name")
if name:
queryset = queryset.filter(Q(name__contains=name))
return queryset
视图配置
filter_backends = [CommonFilter]
✔排序、搜索、自定义过滤可以同时写在
filter_backends列表里,组合使用。
5、分页(只作用于查询全部list接口)
DRF提供3套分页器,全部继承GenericAPIView视图配置 pagination_class = 分页类
① PageNumberPagination(最常用,页码分页)
url格式:?page=2&size=3
from rest_framework.pagination import PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
page_size = 2 # 默认每页2条
page_query_param = "page" # 页码参数名
page_size_query_param = "size" # 用户自定义每页条数
max_page_size = 5 # 最大不能超过5条
② LimitOffsetPagination(偏移分页)
url格式:?offset=4&limit=2
offset:跳过多少条;limit:取多少条
class CommonLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2
limit_query_param = "limit"
offset_query_param = "offset"
max_limit =5
③ CursorPagination(游标分页,适合大数据,不能跳页,只能上一页下一页)
必须指定排序字段,一般按id
class CommonCursorPagination(CursorPagination):
cursor_query_param = "cursor"
page_size =2
ordering = "id"
在视图上启用分页
class BookView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = CommonPageNumberPagination
快速复习总结表
| 模块 | 父类 | 核心方法 | 作用 |
|---|---|---|---|
| 认证 | BaseAuthentication | authenticate | 判断是否登录,返回user |
| 权限 | BasePermission | has_permission | 判断登录用户有没有操作权限 |
| 频率 | SimpleRateThrottle | get_cache_key | 限制访问次数,防刷接口 |
| 过滤排序 | filter_backends | filter_queryset | 对列表数据筛选、排序 |
| 分页 | 三种Pagination | — | 大数据列表分页返回 |
执行顺序:认证 → 权限 → 频率 → 执行视图的list/get/post方法
过滤、排序、分页只在查询全部(list)的时候生效。
如果你想,我可以基于你现有的stu学生app,写一套完整实操案例,把认证、权限、限流、过滤、分页全部跑一遍。