Pydantic constr 与 Field args

问题描述 投票:0回答:3

我想知道以下之间有什么区别:

from pydantic import BaseModel, Field

class Person(BaseModel):
    name: str = Field(..., min_length=1)

并且:

from pydantic import BaseModel, constr

class Person(BaseModel):
    name: constr(min_length=1)

两者似乎都执行相同的验证(甚至当

name
为空字符串时引发完全相同的异常信息)。这只是代码风格的问题吗?其中一个比另一个更受青睐吗?

另外,如果我想包含一个非空字符串列表作为属性,您认为以下哪种方式更好?:

from typing import List
from pydantic import BaseModel, constr

class Person(BaseModel):
    languages: List[constr(min_length=1)]

或者:

from typing import List    
from pydantic import BaseModel, Field

class Person(BaseModel):
    languages: List[str]
    
    @validator('languages', each_item=True)
    def check_nonempty_strings(cls, v):
        if not v:
            raise ValueError('Empty string is not a valid language.')
        return v

编辑: FWIW,我将其用于 FastAPI 应用程序。

编辑2: 对于我的第二个问题,我认为第一个替代方案更好,因为它包含架构中的长度要求(因此它在文档中)

python validation fastapi typing pydantic
3个回答
12
投票

constr 和 Fields 的用途不同。

constr 是一种特定类型,它给出了有关该特定类型的验证规则。所有经典的 python 类型都有等价物。

构造的

参数

    strip_whitespace: bool = False: removes leading and trailing whitespace
    to_lower: bool = False: turns all characters to lowercase
    to_upper: bool = False: turns all characters to uppercase
    strict: bool = False: controls type coercion
    min_length: int = None: minimum length of the string
    max_length: int = None: maximum length of the string
    curtail_length: int = None: shrinks the string length to the set value when it is longer than the set value
    regex: str = None: regex to validate the string against

正如你所看到的,这些参数允许你操纵 str 本身,而不是 pydantic 与该字段的行为。

Field 没有相同的用途,它是一种自定义字段的方式,所有字段不仅仅是 str,它添加了 18 个自定义变量,您可以在here找到。

这只是代码风格的问题吗?其中一个比另一个更受青睐吗?

对于 str 的具体情况,这是代码风格的问题,首选什么并不重要,只有您的用例才重要。

一般来说,最好不要将不同的语法混合在一起,因为你经常需要 Field(),所以你会经常发现它。

一个经典的用例是 api 响应,它以驼峰命名法或帕斯卡命名法发送 json 对象,您可以使用字段别名来匹配这些对象并在 Snake_case 中使用它们的变量。

示例

class Voice(BaseModel):
    name: str = Field(None, alias='ActorName')
    language_code: str = None
    mood: str = None

我个人更喜欢使用 pydantic 类型来明确区分类型规则和字段注释。

基本示例:

class Car(BaseModel):
    description: Union[constr(min_length=1, max_length=64), None] = Field(
        default=None,
        example="something",
        description="Your car description",
    )

在任何情况下,您都应该只使用一种模型结构样式(字段、pydantic 类型或两者同时使用),以实现项目的全局一致性和更好的可读性。

对于你的第二个问题,你是对的,使用 constr 肯定是最好的方法,因为验证规则将被添加到 openapi 文档中。

如果您想了解有关限制和字段规则执行的更多信息,请检查


3
投票

此链接显示了 pydantic 和 mypy 一起工作和不工作的方法: https://lyz-code.github.io/blue-book/coding/python/pydantic_types/#using-constrained-strings-in -列表属性

我的用例的最佳选择是创建一个继承自

pydantic.ConstrainedStr
的类,如下所示:

import pydantic
from typing import List

...

class Regex(pydantic.ConstrainedStr):
    regex = re.compile("^[0-9a-z_]*$")

class Data(pydantic.BaseModel):
    regex: List[Regex]
    # regex: list[Regex] if you are on 3.9+

1
投票

我在

pydantic 1.10.4
中使用
python 3.9
,这是我观察到使用
constr
Field
之间的区别。

from pydantic import BaseModel, Field, FilePath, constr
from typing import Union, Annotated

ContactConstr = constr(regex='\d{3}-\d{3}-\d{4}')
ContactField = Annotated[str, Field(regex='\d{3}-\d{3}-\d{4}')]

class Person(BaseModel):
    contact_with_constr: ContactConstr
    contact_with_field: ContactField
    contacts_with_constr: Union[ContactConstr, list[ContactConstr]]
    contacts_with_field: Union[ContactField, list[ContactField]] # yields incorrect schema

print(Person.schema_json(indent=2))

这会为

contacts_with_field
创建不正确的架构,该架构采用
xxx-xxx-xxxx
形式的单个电话号码或电话号码列表,其中
x
为 0-9。

{
  "title": "Person",
  "type": "object",
  "properties": {
    "contact_with_constr": {
      "title": "Contact With Constr",
      "pattern": "\\d{3}-\\d{3}-\\d{4}",
      "type": "string"
    },
    "contact_with_field": {
      "title": "Contact With Field",
      "pattern": "\\d{3}-\\d{3}-\\d{4}",
      "type": "string"
    },
    "contacts_with_constr": {
      "title": "Contacts With Constr",
      "anyOf": [
        {
          "type": "string",
          "pattern": "\\d{3}-\\d{3}-\\d{4}"
        },
        {
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "\\d{3}-\\d{3}-\\d{4}"
          }
        }
      ]
    },
    "contacts_with_field": {
      "title": "Contacts With Field",
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      ]
    }
  },
  "required": [
    "contact_with_constr",
    "contact_with_field",
    "contacts_with_constr",
    "contacts_with_field"
  ]
}
© www.soinside.com 2019 - 2024. All rights reserved.