【问题标题】:Why doesn't DRF's serializer validate PositiveSmallIntegerField?为什么 DRF 的序列化程序不验证 PositiveSmallIntegerField?
【发布时间】:2017-12-11 00:37:40
【问题描述】:

使用 Django 1.11 和 Django Rest Framework 3.7,我有一个 Person 模型

class Person(models.Model):

    name = models.CharField(max_length=100)
    email = models.EmailField()
    age = models.PositiveSmallIntegerField()

使用 PersonSerializer

class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = ('id', 'name', 'age', 'email')

还有一个 ListCreate 视图

class PersonList(generics.ListCreateAPIView):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer

使用 HTTPie,我可以像这样创建一个 Person:

$ http POST http://127.0.0.1:8000/api/people/ name=Alice age=26 email=alice@example.com
HTTP/1.0 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 60
Content-Type: application/json
Date: Sun, 10 Dec 2017 15:00:28 GMT
Server: WSGIServer/0.1 Python/2.7.11
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "age": 26,
    "email": "alice@example.com",
    "id": 1,
    "name": "Alice"
}

当我使用错误的电子邮件地址创建 Person 时,我收到错误消息:

$ http POST http://127.0.0.1:8000/api/people/ name=Bob age=33 email=oops
HTTP/1.0 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 42
Content-Type: application/json
Date: Sun, 10 Dec 2017 15:01:08 GMT
Server: WSGIServer/0.1 Python/2.7.11
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "email": [
        "Enter a valid email address."
    ]
}

DRF 知道它是一个 EmailField 并自动应用验证,到目前为止一切顺利。

但是,当我创建一个年龄不好(负数)的人时,我没有收到任何错误:

$ http POST http://127.0.0.1:8000/api/people/ name=Charlie age=-10 email=charlie@example
.com
HTTP/1.0 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 65
Content-Type: application/json
Date: Sun, 10 Dec 2017 15:03:25 GMT
Server: WSGIServer/0.1 Python/2.7.11
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "age": -10,
    "email": "charlie@example.com",
    "id": 3,
    "name": "Charlie"
}

现在我的数据库已被不良数据污染。我可以毫无问题地验证我的输入,但是

  • DRF 正确验证了电子邮件字段,让我相信它会根据模型中的字段类型验证输入。
  • 如果我从 html 表单发布,Django 的 ModelForm 将验证电子邮件和年龄字段。
  • 如果我从标准 Django Admin 创建了一个 Person,它也会验证电子邮件和年龄字段。

基于这些事实,我的问题是:

(A) 为什么 DRF 的序列化程序验证 EmailField,而不验证 PositiveSmallIntegerField?

(B) 我应该在哪里验证“年龄”字段以确保它是肯定的?模型?序列化器?查看?

【问题讨论】:

  • 你用的是什么数据库?
  • @StephenRauch SQLite 与内置开发服务器。
  • @epalm 一种可能性,但现在无法测试,所以评论而不是回答:也许 DRF 没有使用表单/管理员使用的默认 0..maxint 但 EmailField 不需要任何定义的参数,使其工作。如果这是真的,请尝试在模型中添加参数(无论如何都是个好主意) - 例如,min_value=0、max_value=120 并查看是否会传递到 DRF。
  • @manassehkatz 查看文档docs.djangoproject.com/en/1.11/ref/models/fields/#integerfield,IntegerField 和 PositiveSmallIntegerField(也没有任何其他字段)都没有 min_value 选项。
  • @epalm - 你是对的!我一直忘记(直到我需要自己做)Django,出于某种我不太理解的原因,没有提供最小值和最大值作为整数字段的一部分。稍后发布答案...

标签: python django validation django-rest-framework


【解决方案1】:

向模型中的字段添加验证器:

from django.core.validators import MinValueValidator
from django.core.validators import MaxValueValidator

class Person(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    age = models.PositiveSmallIntegerField(validators=[MinValueValidator(0), MaxValueValidator(120)])

【讨论】:

  • 谢谢,我更喜欢这个而不是序列化器验证(例如,如果我将正确的验证规则应用于一个序列化器,但“忘记”将它应用于另一个序列化器怎么办?)。在模型中进行验证让我涵盖了任何一种方式。我们是否可以同意将 MinValueValidator(0) 添加到名为 PositiveIntegerField 或 PositiveSmallIntegerField 的字段是荒谬的?
  • 同意!这似乎是 DRF 中的一个错误(缺少功能......)。但是对于 Age,与某些可能的字段不同,确实存在 Max,因此放入 Min & Max 并不是什么大问题。但是当然你可以用一个普通的 SmallIntegerField 做同样的事情。我怀疑整数字段没有本机 Min & Max 函数的原因是它们没有转换为特定于数据库的代码。但是我发现 MySQL 可以直接支持 ORM 函数的其他实例,而 Django 不使用 MySQL 的这些特性,所以我看不到真正的模式。
【解决方案2】:

在 DRF 中,IntegerField 对应 PositiveIntegerField,因此您可以对其设置最大值和最小值限制。

例如:

class PersonSerializer(serializers.ModelSerializer):
    age = serializers.IntegerField(max_value=100, min_value=1)
    class Meta:
        model = Person
        fields = ('id', 'name', 'age', 'email')

【讨论】:

  • 这回答了问题 B,谢谢。但我仍然不满意,因为我不知道 DRF 什么时候基于 Model 进行验证,什么时候没有。
猜你喜欢
  • 1970-01-01
  • 2020-08-14
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
  • 2017-11-09
  • 2018-02-20
  • 1970-01-01
相关资源
最近更新 更多