【问题标题】:How to create a required Boolean field in recent Django REST Framework?如何在最近的 Django REST 框架中创建一个必需的布尔字段?
【发布时间】:2019-08-31 10:14:05
【问题描述】:

如何重现:

  1. 使用django.db.models.BooleanField() 创建一个Django 模型Foo,我们称之为bar
  2. 使用Meta.fields = "__all__" 创建一个非常基本的序列化程序类。
  3. 更新:在现有序列化程序的顶部创建一个PolymorphicSerializer,并使用PolymorphicSerializer 创建一个视图+路径。
  4. 尝试在不提供bar 的情况下发布新的Foo

会发生什么:请求返回 HTTP 201 Created 并包含 bar=False

应该发生什么:请求显然应该失败,并返回表明bar 是必需的。

我在模型上也有一个必需的 IntegerField,并且尝试在没有 that 参数的情况下发布实例数据确实会导致“必需”错误消息。

我没有使用 Django 表单,所以 thisthis 不是重复的。我试过this workaround,但del kwargs['required'] 失败,出现“KeyError:'required'”。 This other workaround 似乎没有做任何事情,可能是因为该字段也是在模型上定义的。 this workaround 同上。

使用 djangorestframework==3.9.2 和 django==2.1.7。

【问题讨论】:

  • 可能是 DRF 中的序列化代码的错误,它可能错误地将缺少值解释为“不正确”,因此错误地解释为“错误”。您可以尝试在序列化程序中将其覆盖为 NullableBoolenField (已经有一段时间了,所以我可能有错误的字段名称)应该理解 null 状态,然后为该字段编写一个验证器,抛出一个 validationError if val is None

标签: django django-rest-framework


【解决方案1】:

按照以下建议将extra_kwargs 添加到您的ModelSerializer

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo
        fields = "__all__"
        extra_kwargs = {'bar': {'required': True}}

bar 字段中设置required=True 参数。

如果您还有其他问题,请咨询 cmets 部分。

【讨论】:

  • 打败我,决定安装所有匹配的版本并首先测试代码......这确实有效。回复是{ "bar": [ "This field is required." ] }
  • 正如我所提到的,这是我尝试过的事情之一。我再试一次。
  • 不,不起作用。可能是因为此端点使用了PolymorphicSerializer - 必填字段仅在其中一个类上。
【解决方案2】:

免责声明:这不是对 OP 的回答,但我在解释为​​什么 DRF 有这种行为


简而言之,只有当您尝试通过 HTML 表单 (DRF Web API Console) POST 时才会发生这种情况。如果你尝试通过POSTMAN Console, it will raise the Validation Error


为什么会这样??

如果您在这两种情况下检查 request.data 的类型,它将是

| Request Source    | Input data type   |
|------------------ |-----------------  |
| DRF HTML Input    | QueryDict         |
| POSTMAN API call  | dict              |

变化发生在哪里?

导致该行为的 get_value() method of Field 类。在这种情况下,检查发生在,

if html.is_html_input(dictionary):
    ....... do something

从那个 if 子句中,EMPTY/BLANK 值变成了False



解决方案

为您的序列化程序创建自定义布尔字段覆盖它的 get_value() 方法

from rest_framework.fields import empty


class CustomBooleanField(serializers.BooleanField):
    def get_value(self, dictionary):
        return dictionary.get(self.field_name, empty)


class FooSerializer(serializers.ModelSerializer):
    bar = CustomBooleanField(required=True)

    class Meta:
        fields = '__all__'
        model = Foo

截图

1. DRF Web API 控制台
2。 POSTMAN API 控制台

【讨论】:

  • 运行 Django 测试用例时会发生这种情况。
  • 我的回答没有多大帮助?
  • 无论如何,你能分享我可以模拟错误的最小测试代码吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多