【发布时间】:2023-03-12 20:37:01
【问题描述】:
我在确定在 Django 中引入验证逻辑的最佳(阅读:DRY 和可维护)位置时遇到了一些问题,即在模型、表单和 DRF 序列化程序之间。
我已经使用 Django 多年,并且一直遵循处理模型、表单和 REST API 端点验证的各种约定。我已经尝试了很多变体来确保整体数据完整性,但最近我遇到了一些绊脚石。以下是我在浏览了许多文章、SO 帖子和票证后尝试过的简要列表:
模型级别的验证;即,通过覆盖
myModel.clean()(以及特定于字段和唯一的方法)在调用myModel.save()之前确保我的所有自定义约束都匹配。为此,我确保在myForm.clean()(用于表单——管理面板实际上已经这样做)和mySerializer.validate()(用于 DRF 序列化程序)方法中调用了myModel.full_clean()。在表单和序列化程序级别进行验证,为可维护的 DRY 代码调用共享方法。
在表单和序列化程序级别进行验证,每种方法都有不同的方法以确保最大的灵活性(即,当表单和端点具有不同的约束时)。
当表单和序列化程序具有相同的约束时,方法一对我来说似乎是最直观的,但在实践中有点混乱;首先,数据由表单或序列化程序自动清理和验证,然后实例化模型实体,并再次运行更多验证——这有点复杂,可能会变得复杂。
方法三是 Django Rest Framework 3.0 版本推荐的方法;他们消除了很多model.save() 钩子,并且更愿意将验证留给应用程序的面向用户的方面。这对我来说很有意义,因为 Django 的基本 model.save() 实现不会调用 model.full_clean()。
所以,方法二对我来说似乎是最好的总体概括结果;验证存在于一个不同的地方 - 在模型被触及之前 - 由于共享验证逻辑,代码库不那么混乱/更干燥。
不幸的是,我遇到的大部分问题是让 Django Rest Framework 的序列化程序配合。这三种方法都适用于表单,实际上适用于大多数 HTTP 方法(尤其是在 POST 以创建实体时)——但在更新现有实体(PUT、PATCH)时似乎没有一种方法能很好地发挥作用。
长话短说,事实证明,当传入数据不完整时(但在其他情况下是有效的——通常是 PATCH 的情况),验证传入的数据相当困难。请求数据可能只包含一些字段——那些包含不同/新信息的字段——并且模型实例的现有信息为所有其他字段维护。事实上,DRF issue #4306 完美地总结了这一特殊挑战。
我还考虑过在视图集级别运行自定义模型验证(在填充 serializer.validated_data 并且存在 serializer.instance 之后,但在调用 serializer.save() 之前),但我仍在努力想出由于处理更新的复杂性,这是一种简洁、通用的方法。
TL;DR Django Rest Framework 使得在一个明显的地方编写干净、可维护的验证逻辑有点困难,特别是对于依赖于现有模型数据和传入请求数据的混合的部分更新.
我很想请一些 Django 专家来评估他们的工作,因为我没有看到任何方便的解决方案。
谢谢。
【问题讨论】:
-
你找到答案了吗?
-
是的,我也很好奇!
标签: python django validation serialization django-rest-framework