官方原文链接
本系列文章 github 地址
转载请注明出处

验证器

大多数情况下,您在 REST framework 中处理验证时,只需依赖默认的字段验证,或者在序列化类或字段类上编写明确的验证方法。

但是,有时你会希望将验证逻辑放置到可重用组件中,以便在整个代码库中轻松地重用它。这可以通过使用验证器函数和验证器类来实现。

REST framework 中的验证

Django REST framework 序列化器中的验证与 Django ModelForm 类中验证的工作方式有点不同。

使用 ModelForm,验证一部分在表单上执行,一部分在模型实例上执行。使用 REST framework ,验证完全在序列化类上执行。这是有优势的,原因如下:

  • 它使问题适当的分离,让代码行为变的更加清晰。
  • 使用快捷的 ModelSerializer 类和使用显式的 Serializer 类可以轻松切换。任何用于 ModelSerializer 的验证行为都很容易复制。
  • 打印序列化类实例的 repr 将会显示它应用的验证规则。在模型实例上没有额外的隐藏验证行为(因为全在序列化类上)。

当你使用 ModelSerializer 时,所有验证都会自动为你处理。如果你想要改为使用 Serializer 类,那么你需要明确定义验证规则。

举个栗子

作为 REST framework 如何使用显式验证的示例,我们将采用一个简单的模型类,该类具有唯一性约束的字段。

class CustomerReportRecord(models.Model):time_raised = models.DateTimeField(default=timezone.now, editable=False)reference = models.CharField(unique=True, max_length=20)description = models.TextField()
复制代码

下面是一个基本的 ModelSerializer ,我们可以使用它来创建或更新 CustomerReportRecord 的实例:

class CustomerReportSerializer(serializers.ModelSerializer):class Meta:model = CustomerReportRecord
复制代码

现在使用 manage.py shell 打开 Django shell

>>> from project.example.serializers import CustomerReportSerializer
>>> serializer = CustomerReportSerializer()
>>> print(repr(serializer))
CustomerReportSerializer():id = IntegerField(label='ID', read_only=True)time_raised = DateTimeField(read_only=True)reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>])description = CharField(style={'type': 'textarea'})
复制代码

这里有趣的是 reference 字段。我们可以看到唯一性约束由序列化字段上的验证器明确执行。

由于这种更明确的风格,REST framework 包含一些在核心 Django 中没有的验证器类。这些类在下面详细说明。


UniqueValidator

该验证器可用于在模型字段上强制实施 unique=True 约束。它需要一个必需的参数和一个可选的 messages 参数:

  • queryset 必须 - 这是验证唯一性的查询集。
  • message - 验证失败时使用的错误消息。
  • lookup - 用于查找已验证值的现有实例。默认为 'exact'

这个验证器应该应用于序列化字段,如下所示:

from rest_framework.validators import UniqueValidatorslug = SlugField(max_length=100,validators=[UniqueValidator(queryset=BlogPost.objects.all())]
)
复制代码

UniqueTogetherValidator

此验证器可用于在模型实例上强制实施 unique_together 约束。它有两个必需的参数和一个可选的 messages 参数:

  • queryset 必须 - 这是验证唯一性的查询集。
  • fields 必须 - 一个存放字段名称的列表或者元组,这个集合必须是唯一的(意思是集合中的字段代表的一组值不能同时出现在两条数据中)。这些字段必须都是序列化类中的字段。
  • message - 验证失败时使用的错误消息。

验证器应该应用于序列化类,如下所示:

from rest_framework.validators import UniqueTogetherValidatorclass ExampleSerializer(serializers.Serializer):# ...class Meta:# ToDo items belong to a parent list, and have an ordering defined# by the 'position' field. No two items in a given list may share# the same position.validators = [UniqueTogetherValidator(queryset=ToDoItem.objects.all(),fields=('list', 'position'))]
复制代码

注意: UniqueTogetherValidation 类总是施加一个隐式约束,即它所应用的所有字段都是按需处理的。具有 default 值的字段是一个例外,因为它们总是提供一个值,即使在用户输入中省略了这个值。


UniqueForDateValidator

UniqueForMonthValidator

UniqueForYearValidator

这些验证器可用于强制实施模型实例上的 unique_for_dateunique_for_monthunique_for_year 约束。他们有以下参数:

  • queryset 必须 - 这是验证唯一性的查询集。
  • field 必须 - 在给定日期范围内需要被验证唯一性的字段的名称。该字段必须是序列化类中的字段。
  • date_field 必须 - 将用于确定唯一性约束的日期范围的字段名称。该字段必须是序列化类中的字段。
  • message - 验证失败时使用的错误消息。

验证器应该应用于序列化类,如下所示:

from rest_framework.validators import UniqueForYearValidatorclass ExampleSerializer(serializers.Serializer):# ...class Meta:# Blog posts should have a slug that is unique for the current year.validators = [UniqueForYearValidator(queryset=BlogPostItem.objects.all(),field='slug',date_field='published')]
复制代码

我解释下,上面例子的意思是,在 published 日期所在的年份中,slug 字段的值必须唯一,注意,不是要和 published 完全相等的日期,而是年份相等。unique_for_dateunique_for_month 同理。

用于验证的日期字段应该始终存在于序列化类中。你不能简单地依赖模型类 default=...,因为默认值在验证运行之后才会生成。

你可能需要使用几种样式,具体取决于你希望 API 如何展现。如果你使用的是 ModelSerializer ,可能只需依赖 REST framework 为你生成的默认值,但如果你使用的是 Serializer 或需要更明确的控制,请使用下面演示的样式。

与可写日期字段一起使用。

如果你希望日期字段是可写的,唯一值得注意的是你应该确保它始终可用于输入数据中,可以通过设置 default 参数或通过设置 required=True 来实现。

published = serializers.DateTimeField(required=True)
复制代码

与只读日期字段一起使用。

如果你希望日期字段可见,但用户无法编辑,请设置 read_only=True 并另外设置 default=... 参数。

published = serializers.DateTimeField(read_only=True, default=timezone.now)
复制代码

该字段对用户不可写,但默认值仍将传递给 validated_data

与隐藏的日期字段一起使用。

如果你希望日期字段对用户完全隐藏,请使用 HiddenField。该字段类型不接受用户输入,而是始终将其默认值返回到序列化类中的 validated_data

published = serializers.HiddenField(default=timezone.now)
复制代码

注意: UniqueFor<Range>Validation 类总是施加一个隐式约束,即它所应用的所有字段都是按需处理的。具有 default 值的字段是一个例外,因为它们总是提供一个值,即使在用户输入中省略了这个值。


Advanced field defaults

在序列化类的多个字段中应用的验证器有时不需要由 API 客户端提供的字段输入,但它可以用作验证器的输入。

有两种模式可能需要这种验证:

  • 使用 HiddenField 。该字段将出现在 validated_data 中,但不会用在序列化输出表示中。
  • 使用 read_only=True 的标准字段,同时也包含 default=... 参数。该字段将用于序列化输出表示中,但不能由用户直接设置。

REST framework 包含一些在这种情况下可能有用的默认值。

CurrentUserDefault

可用于表示当前用户的默认类。为了使用它,在实例化序列化类时,'request' 必须作为上下文字典的一部分提供。

owner = serializers.HiddenField(default=serializers.CurrentUserDefault()
)
复制代码

CreateOnlyDefault

可用于在 create 操作期间仅设置默认参数的默认类。在 update 期间,该字段被省略。

它接受一个参数,这是在 create 操作期间应该使用的默认值或可调用参数。

created_at = serializers.DateTimeField(read_only=True,default=serializers.CreateOnlyDefault(timezone.now)
)
复制代码

验证器的限制

有一些不明确的情况,你需要显示处理验证,而不是依赖 ModelSerializer 生成的默认序列化类。

在这些情况下,你可能希望通过为序列化类 Meta.validators 属性指定一个空列表来禁用自动生成的验证器。

可选字段

默认情况下 "unique together" 验证强制所有字段都是 required=True。在某些情况下,你可能希望显式将 required=False 应用于其中一个字段,在这种情况下,验证所需的行为是不明确的。

在这种情况下,你通常需要从序列化类中排除验证器,并且在 .validate() 方法中或在视图中显式地编写验证逻辑。

例如:

class BillingRecordSerializer(serializers.ModelSerializer):def validate(self, data):# Apply custom validation either here, or in the view.class Meta:fields = ('client', 'date', 'amount')extra_kwargs = {'client': {'required': 'False'}}validators = []  # Remove a default "unique together" constraint.
复制代码

更新嵌套序列化类

将更新应用于现有实例时,唯一性验证器将从唯一性检查中排除当前实例。当前实例在唯一性检查的上下文中可用,因为它作为序列化程序中的一个属性存在,最初在实例化序列化类时已使用 instance=... 传递。

在嵌套序列化类上进行更新操作时,无法应用此排除,因为该实例不可用。

你可能又一次需要明确地从序列化类中移除验证器,并将验证约束的代码显式写入 .validate() 方法或视图中。

调试复杂的案例

如果你不确定 ModelSerializer 类的默认行为,那么运行 manage.py shell 并打印序列化类实例通常是一个好主意,以便你可以检查它自动生成的字段和验证器。

>>> serializer = MyComplexModelSerializer()
>>> print(serializer)
class MyComplexModelSerializer:my_fields = ...
复制代码

还要记住,在复杂情况下,明确定义序列化类通常会更好,而不是依赖默认的 ModelSerializer 行为。虽然这样会写更多的代码,但确保了最终的行为更加透明。


编写自定义验证器

你可以使用 Django 现有的验证器,也可以编写自定义验证器。

基于函数

验证器可以是任何可调用对象,在失败时引发 serializers.ValidationError

def even_number(value):if value % 2 != 0:raise serializers.ValidationError('This field must be an even number.')
复制代码

字段级验证

你可以通过向 Serializer 子类添加 .validate_<field_name>方法来指定自定义字段级验证。

基于类

要编写一个基于类的验证器,请使用 __call__ 方法。基于类的验证器很有用,因为它们允许参数化和重用行为。

class MultipleOf(object):def __init__(self, base):self.base = basedef __call__(self, value):if value % self.base != 0:message = 'This field must be a multiple of %d.' % self.baseraise serializers.ValidationError(message)
复制代码

使用 set_context()

在一些高级的情况下,你可能想要在验证器中获取正在被验证的序列化字段。这时,你可以通过在基于类的验证器上声明 set_context 方法来完成此操作。

def set_context(self, serializer_field):# Determine if this is an update or a create operation.# In `__call__` we can then use that information to modify the validation behavior.self.is_update = serializer_field.parent.instance is not None
复制代码

Django REST framework API 指南(12):验证器相关推荐

  1. Django REST framework API 指南(2):响应

    Django REST framework API 指南(1):请求 Django REST framework API 指南(2):响应 Django REST framework API 指南(3 ...

  2. Django REST framework API 指南(11):序列化·关系

    官方原文链接 本系列文章 github 地址 转载请注明出处 Serializer 关系 关系字段用于表示模型关系. 它们可以应用于 ForeignKey,ManyToManyField 和 OneT ...

  3. Django REST framework API 指南(25):状态码

    官方原文链接 本系列文章 github 地址 转载请注明出处 状态码 不建议在你的响应中使用裸露(直接使用数字)的状态码. REST framework 包含一组命名常量,你可以使用它们使代码更加清晰 ...

  4. Django REST framework API开发

    REST 介绍 RESTful API 设计 实现API的两种方式 FBV 视图函数 urlpatterns = [url(r'^user/$', views.user),url(r'^user/ad ...

  5. Django REST Framework API Guide 01

    之前按照REST Framework官方文档提供的简介写了一系列的简单的介绍博客,说白了就是翻译了一下简介,而且翻译的很烂.到真正的生产时,就会发现很鸡肋,连熟悉大概知道rest framework都 ...

  6. Django REST Framework API Guide 02

    本节大纲 1.Generic Views 2.ViewSets  1.Generic Views CBV的主要的一个优点就是极大的允许了对于代码的从用.自然,rest framework取其优势,提供 ...

  7. Django REST Framework API Guide 07

    本节大纲 1.Permissions 2.Throttling Permissions 权限是用来授权或者拒绝用户访问API的不同部分的不同的类的.基础的权限划分 1.IsAuthenticated ...

  8. JWT验证机制【刘新宇】【Django REST framework中使用JWT】

    JWT 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证.我们不再使用Session认证机制,而使用Json Web Token认证机制. 什么是JWT Json web t ...

  9. 谈谈Django REST Framework(DRF)中的序列化器

    摘要 Django REST Framework(DRF)是一个强大的工具,可以帮助我们构建和处理RESTful API.其中的序列化器(Serializers)是其核心组件之一,它允许我们快速有效地 ...

最新文章

  1. Linux Shell 常用快捷键
  2. 关于「Xception」和「DeepLab V3+」的那些事
  3. 微计算机和微处理器的区别,CPU和微处理器的区别
  4. 1288:三角形最佳路径问题-2019-07-04
  5. 【Java从0到架构师】Zookeeper - 安装、核心工作机制、基本命令
  6. 单链表的读取、插入与删除
  7. hibernate oracle 读写分离_ASP.NET CORE 国产最火前后端完全分离框架BCVP
  8. Python学习—2048小游戏等4个小练习
  9. 第六章 Realm及相关对象——《跟我学Shiro》[张开涛]
  10. macOS Catalina 10.15.7 ISO/CDR 虚拟机镜像下载
  11. allegro 自定义快捷键
  12. oracle中文转全拼音,汉字转拼音的Oracle函数
  13. css定位(二)---css中粘性定位(sticky)---C3新增属性
  14. php post伪装ip,PHP中用CURL伪造IP来源的方法
  15. mac下如何解压7z
  16. 很火的区块链头部游戏《Axie Infinity》单日盈收竟与王者荣耀争锋,它是什么?
  17. java基础复习——day18(Stream流 ; 反射)
  18. Steve Hui:云联云是中国云计算的最好切入点(4月刊推荐)
  19. Lettuce: Connection to xxx not allowed. This partition is not known in the cluster view.
  20. Unity 编辑器开发实战【Custom Editor】- 为UI视图制作动画编辑器

热门文章

  1. 李彦宏:用“工程思维”做自动驾驶
  2. 吴军:既能得诺贝尔奖,又能生产高科技产品,美国的科研机制是如何运行的?...
  3. 自动驾驶出行,进入下半场
  4. 希尔伯特著名的第六问题 – 原来麦克斯韦早就有解?
  5. 5G新标准将延迟3个月发布,但5G“新战场”已经明确
  6. CES 2019开胃菜竟然是芯片,英特尔 英伟达 高通 华为 AMD已经开打!
  7. 边缘计算芯片格局分析
  8. 包揽全球50%以上份额,中美发力超级计算
  9. “芯痛”之下阿里苦心研发NPU AI芯片究竟哪款PU更厉害?
  10. 新技术:如何用VR训练机器人?