ORM与验证的分离
我在使用Django框架,想知道模型验证应该放在哪里比较合适。大致有两种情况:
- 在模型的保存方法中进行验证,如果违反了业务规则,就抛出IntegrityError或其他异常
- 通过表单和内置的clean_*功能来验证数据
从一个角度来看,答案很明显:应该使用基于表单的验证。因为ORM(对象关系映射)是ORM,而验证是完全不同的概念。比如说CharField:forms.CharField可以指定最小长度,但models.CharField却不行。
那么,Django的django.db.models里那些验证功能到底是干嘛的呢?我可以指定CharField不能为空,可以使用EmailField、FileField、SlugField,这些验证都是在Python中进行的,而不是在关系数据库管理系统(RDBMS)中。此外,还有一个URLField,它会检查URL的存在性,这涉及到一些非常复杂的逻辑。
另一方面,如果我有一个实体,我希望确保它在保存时不会处于不一致的状态,无论它是来自表单还是通过一些内部算法修改或创建的。我有一个包含名称字段的模型,我希望这个名称应该超过一个字符。我还有最小年龄和最大年龄字段,如果最小年龄大于最大年龄,那就没什么意义了。那么,我应该在保存方法中检查这些条件吗?
模型验证的最佳实践是什么?
5 个回答
我不确定这是不是最好的做法,但我通常会在把数据存入数据库之前,先在客户端和服务器端都进行验证。我知道这需要更多的工作,但可以通过在使用之前设置一些值,然后保持这些值来实现。
你也可以尝试在调用验证函数时,使用 **kwargs 来设置大小限制,这个验证函数会在 put() 调用之前执行。
你有两个选择,它们是两种不同的东西。
- 基于表单的验证可以看作是语法验证 + 将HTTP请求中的参数从文本转换为Python的数据类型。
- 基于模型的验证可以看作是语义验证,有时会使用在HTTP或表单层面无法获得的上下文信息。
当然,还有第三层是在数据库中,这里会强制执行一些约束条件,这些约束可能在其他地方无法检查,因为数据库可能会被多个请求同时更新(比如唯一性约束、乐观锁定)。
数据库/模型验证
存储在数据库中的数据必须始终保持某种特定的形式或状态。比如说:必须有名字、姓氏、外键、唯一性约束。这就是你应用程序逻辑所在的地方。无论你认为数据来自哪里——在这里都应该进行“验证”,如果不符合要求,就要抛出异常。
表单验证
输入的数据应该看起来是正确的。即使这些数据是通过其他方式(比如管理员操作或API调用)输入的,也没关系。举个例子:人的名字长度、句子的正确大小写等等。
例子1:一个对象有一个开始日期和一个结束日期。开始日期必须总是在结束日期之前。你应该在哪里进行验证呢?当然是在模型里!想象一下,如果你从其他系统导入数据,你肯定不希望这些不符合条件的数据被接受。
例子2:密码确认。你在数据库中有一个存储密码的字段。但是在你的表单上,你显示了两个字段:密码1和密码2。只有表单负责比较这两个字段,确保它们是相同的。表单验证通过后,你就可以安全地把密码1存入数据库作为密码。