ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Django REST framework 3.16 版本解读:Django 5.x/Python 3.13 支持与 UniqueConstraint 校验增强

Django REST framework 3.16 版本解读:Django 5.x/Python 3.13 支持与 UniqueConstraint 校验增强 Django REST framework 3.16 版本解读Django 5.x/Python 3.13 支持与 UniqueConstraint 校验增强【免费下载链接】django-rest-frameworkWeb APIs for Django. 项目地址: https://gitcode.com/gh_mirrors/dj/django-rest-frameworkDjango REST framework下称 DRF3.16 于 2025 年 3 月 28 日发布是一次以“对齐上游 Django 生态”为核心的正式版本。本文将逐项拆解该版本在 Django/Python 版本支持矩阵、Django 5.1LoginRequiredMiddleware兼容策略、UniqueConstraint校验器生成改进三方面的实际变化并结合 3.16 发布说明、版本发布记录 与 field_mapping.py 等仓库源码说明每个新特性的落地方式、行为影响与注意事项帮助升级到 3.16 的团队评估改动面。一、版本支持矩阵更新Django 4.2 起跳拥抱 5.2 LTS 与 Python 3.133.16 是 DRF 在 2025 年推出的重要版本其核心定位是“改善对上游 Django 与 Python 的支持”其中部分改动会改变既有特性的行为详见 release-notes.md 3.16.0 段落。1.1 支持范围速览项目3.16 之后的支持范围说明Django4.2 起完整支持 5.1 与 5.2 LTS最低版本从 3.2 提升至 4.2Python3.9 起新增 3.13移除对 Python 3.8 的支持依据3.16 发布说明 明确声明完整支持 Django 5.1 与即将到来的 5.2 LTS以及 Python 3.13当前最低 Django 版本为 4.2、最低 Python 版本为 3.9。release-notes.md 的 3.16.0 条目补充了 PR 级别的证据官方 Django 5.1 与LoginRequiredMiddleware支持#9514、#9657、Django 5.2a1 支持#9634、Python 3.13 支持#9527、#9556、移除 Python 3.8 支持#9670随后的 3.16.1 补丁则清理了 Python 3.8 及以下的backports.zoneinfo条件依赖#9681。1.2 升级前需要了解的两点最低版本门槛提高仍运行在 Django 4.2 以下如 Django 3.2或 Python 3.8 环境的项目需要先升级运行时才能使用 3.16。部分行为变化3.16.0 条目明确提示“一些修复可能改变既有特性的行为”其中最典型的就是UniqueConstraint对可空字段的校验改进见下文第三节建议升级后重点回归唯一性校验相关的用例。二、与 Django 5.1LoginRequiredMiddleware的兼容策略API 视图默认豁免Django 5.1 引入了全局登录要求中间件LoginRequiredMiddleware。DRF 3.16 对此的官方态度是该中间件可正常与 DRF 并存使用但对 API 视图默认不生效因为 DRF 的认证/授权机制应当由认证类与权限类共同决定而非由中间件在视图执行前统一拦截。2.1 为什么 API 视图要豁免DRF 在 认证文档的专门章节 中给出了两点理由决策时机问题DRF 的认证基于认证类authentication classes与权限类permission classes其最终结果要在中间件执行之后才能确定中间件先行拦截会破坏这一机制响应语义问题未认证的 API 请求应返回 401 状态码而LoginRequiredMiddleware默认将未认证请求重定向到登录页这不适合 API 场景。2.2 源码层面的实现证据在 views.py 的APIView.as_view()中DRF 通过显式设置view.login_required False将自身视图从该中间件中剔除view super().as_view(**initkwargs) view.cls cls view.initkwargs initkwargs # Exempt all DRF views from Djangos LoginRequiredMiddleware. Users should set # DEFAULT_PERMISSION_CLASSES to rest_framework.permissions.IsAuthenticated instead view.login_required False # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)同样的处理也出现在 viewsets.py 中。也就是说无论你使用的是基于APIView的类视图还是基于ViewSet的视图集只要经由 DRF 的as_view()入口注册都会被标记为login_required False从而绕过 Django 5.1 的全局登录中间件。2.3 正确的替代做法用认证/权限类表达登录要求既然中间件对 API 不生效登录要求的表达应完全交给 DRF 自身的策略体系。全局配置示例如下与 认证文档 中的DEFAULT_AUTHENTICATION_CLASSES用法一致REST_FRAMEWORK { DEFAULT_AUTHENTICATION_CLASSES: [ rest_framework.authentication.SessionAuthentication, rest_framework.authentication.BasicAuthentication, ], DEFAULT_PERMISSION_CLASSES: [ rest_framework.permissions.IsAuthenticated, ], }按视图粒度配置APIView子类from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView class ExampleView(APIView): authentication_classes [SessionAuthentication, BasicAuthentication] permission_classes [IsAuthenticated] def get(self, request, formatNone): content { user: str(request.user), # django.contrib.auth.User 实例 auth: str(request.auth), # 未认证时为 None } return Response(content)函数式视图则使用api_view配合authentication_classes与permission_classes装饰器写法与类视图等价。认证本身只负责“识别凭据”是否放行由权限类决定这一点在 认证文档 中也有明确说明——不要把认证与授权混为一谈。三、UniqueConstraint校验器生成改进可空字段与条件约束3.16 对UniqueConstraint的校验支持做了实质性增强这也是该版本中“可能改变既有行为”的核心点。DRF 的ModelSerializer在构建字段时会通过 field_mapping.py 中的get_unique_validators()把模型层约束翻译成序列化器层的校验器。3.1 核心实现get_unique_validators()做了什么get_unique_validators(field_name, model_field)的完整逻辑如下def get_unique_validators(field_name, model_field): Returns a list of UniqueValidators that should be applied to the field. field_set {field_name} conditions { c.condition for c in model_field.model._meta.constraints if isinstance(c, models.UniqueConstraint) and set(c.fields) field_set } if getattr(model_field, unique, False): conditions.add(None) if not conditions: return unique_error_message get_unique_error_message(model_field) queryset model_field.model._default_manager for condition in conditions: condition_fields ( set(condition.referenced_base_fields) if condition is not None else set() ) # Only use UniqueValidator if the union of field and condition fields is 1 # (i.e. no additional fields referenced in conditions) if len(field_set | condition_fields) 1: yield UniqueValidator( querysetqueryset if condition is None else queryset.filter(condition), messageunique_error_message, )关键点可以拆成三层识别约束遍历模型_meta.constraints只关注字段集合恰好等于当前序列化字段的models.UniqueConstraint并收集其condition条件表达式若模型字段本身还带uniqueTrue则追加一个无条件None条件。推导条件字段通过condition.referenced_base_fields取出条件表达式中引用到的模型字段。决定校验器形态只有“当前字段 ∪ 条件引用字段”数量为 1即条件没有引用额外字段时才生成UniqueValidator此时如果存在条件查询集会被过滤为queryset.filter(condition)从而在序列化校验阶段就复现数据库约束的语义。3.2 对可空字段与条件约束的具体改进结合 release-notes.md 中 3.16.0 的 Bug fixes 列表本次改动的落点包括修复UniqueConstraint中包含可空字段时抛错的问题#9531此前对含可空字段的UniqueConstraint生成校验器时可能直接报错3.16 起这类约束能够被正确翻译为序列化器校验修复unique_together校验器未尊重UniqueConstraint条件字段的问题#9360条件中引用的字段现在会进入校验器生成逻辑的判断修复unique_together校验对带source属性的字段的处理#94823.16.1 中进一步修复 #9688。3.3 测试用例印证仓库测试 tests/test_validators.py 为此维护了一整套覆盖模型与用例UniqueConstraintModel#920 附近、UniqueConstraintNullableModel#970 附近、UniqueConstraintBlankModel#982 附近对应 issue #9750 的“条件化UniqueConstraint配可空/空字符串字段”场景、UniqueConstraintNullsDistinctModel#1002 附近、UniqueConstraintCustomMessageCodeModel#1017 附近等模型覆盖了条件约束、可空字段、空白字段、nulls_distinct以及自定义错误消息码等形态TestUniqueConstraintValidation#1062 起等测试类则验证序列化器实际生成的校验器列表例如断言某个条件化UniqueConstraint会生成带conditionQ: (AND: (race_name, example))的UniqueTogetherValidator以及字段级UniqueValidator的存在性。这意味着 3.16 起模型上声明的条件化唯一约束可以在序列化层获得更接近数据库行为的校验体验——在写入数据库之前就拦截重复数据而不是依赖数据库抛IntegrityError。3.4 使用提示若你的模型使用了带condition的条件化UniqueConstraint升级到 3.16 后请重新生成并核对ModelSerializer的字段校验器行为可能与旧版本不同条件引用了当前字段之外的其他字段时会走UniqueTogetherValidator路径而非字段级UniqueValidator相关字段需要同时出现在序列化器中3.16.1 还修复了unique_together校验与SerializerMethodField搭配时的回归#9712如果同时使用这些特性建议直接升级到 3.16.1 或更高版本。四、其余修复与改进3.16 还包含大量文档、内部基础设施类型标注、测试矩阵、依赖与弃用清理以及安全与整体行为层面的修复。值得关注的部分包括支持 Django 2.1 测试客户端自动序列化 JSON 数据#6511及随后的回归修复#9615为属性property内抛出的AttributeError增加保护#9455避免被误当作“字段不存在”处理修复DecimalField的 min/max 值接受整数时的噪音告警#9515移除AutoSchema._get_reference等长期弃用的接口#9525、#9441新增哈萨克语翻译3.16.1见 release-notes.md并同步更新了中、韩、德、西、土等多语言翻译。完整清单请以 版本发布记录 页面为准3.16.0 与 3.16.1 两个小版本均有独立条目。五、升级建议结合本仓库的 3.16 发布说明 与源码实现给出如下升级检查清单运行时版本确认 Django ≥ 4.2、Python ≥ 3.9如需 Python 3.13 或 Django 5.x本版本是必要条件。认证策略如果 Django 5.1 项目启用了LoginRequiredMiddleware确认 API 路由全部经由 DRF 的as_view()注册会自动豁免并将登录要求迁移到DEFAULT_AUTHENTICATION_CLASSES/DEFAULT_PERMISSION_CLASSES或视图级authentication_classes/permission_classes。唯一性校验回归重点回归所有使用了UniqueConstraint尤其是带condition或可空字段的模型对应序列化器确认新生成的校验器行为符合预期。弃用接口清理检查代码中是否引用了 3.16 移除的旧接口如AutoSchema._get_reference、request 包装器中的旧 API。浏览补丁版如有条件优先升级到 3.16.1以获取unique_together与SerializerMethodField回归修复及翻译更新。【免费下载链接】django-rest-frameworkWeb APIs for Django. 项目地址: https://gitcode.com/gh_mirrors/dj/django-rest-framework创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表