【发布时间】:2015-08-03 16:49:39
【问题描述】:
我目前有一个用户模型,它在用户名字段上具有唯一约束。我的理解是,我可以在序列化程序中的用户名字段上添加一个 UniqueValidator,或者当我去保存模型然后处理它时让数据库抛出一个 IntegrityError。
似乎在序列化程序上添加 UniqueValidator 只会创建额外的查询并且性能会更差,但是否有充分的理由在序列化程序上进行所有验证,而不是让数据库抛出错误?
【问题讨论】:
我目前有一个用户模型,它在用户名字段上具有唯一约束。我的理解是,我可以在序列化程序中的用户名字段上添加一个 UniqueValidator,或者当我去保存模型然后处理它时让数据库抛出一个 IntegrityError。
似乎在序列化程序上添加 UniqueValidator 只会创建额外的查询并且性能会更差,但是否有充分的理由在序列化程序上进行所有验证,而不是让数据库抛出错误?
【问题讨论】:
当然。在 DRF 序列化器中负责两件事:
dict <-> model
验证非常重要。这有效地使序列化程序成为您数据库的网关。它检查数据,如果数据不好,它会编译可以返回给用户的错误。如果数据有效,则序列化程序可以进一步用于与数据库交互,例如创建/更新模型。然而,这有影响。现在假设你的序列化器有嵌套的序列化器:
class FooSerializer(Serializer):
...
class BarSerializer(Serializer):
foo = FooSerializer()
def create(self, validated_data):
foo = self.fields['foo'].create(validated_data['foo'])
# create bar here
如果BarSerializer 不强制某些字段的唯一性,则在其create 中,可以在创建bar 之前创建foo,这可能由于违反唯一性而在数据库中失败。这是不希望的,因为 REST 请求应该是原子的(请求应该成功或失败,但绝不会部分成功)。有一些方法可以通过使用数据库事务来处理这个问题,但这会带来不必要的复杂性。但是,如果在序列化程序中强制执行唯一性,则创建 bar 失败的可能性要小得多。请注意,它仍然可能在并发应用程序中失败(两个请求尝试同时执行相同的操作,第一个请求在第二个请求的 foo 序列化程序验证数据并保存 bar 之间创建 bar)。检查唯一性只是降低了失败的风险,并允许请求更加原子化,同时减少数据库维护开销。
【讨论】: