【问题标题】:pydantic custom data type for phone number : value_error.missing电话号码的 pydantic 自定义数据类型:value_error.missing
【发布时间】:2022-01-21 14:54:44
【问题描述】:

用户的mysql架构

user_id     binary(16) 
first_name  varchar(32) 
last_name   varchar(32) 
email       varchar(255)
phone       varchar(32) 
role        enum('member','admin','operator')
created_on  datetime
updated_on  datetime
id   varchar(32)

我的 pydantic 模型是

class UserPatchEntity(BaseModel):
    user_id: Optional[UUID]
    first_name: Optional[str] = Field(min_length=1, max_length=32)
    last_name: Optional[str] = Field(min_length=1, max_length=32)
    email: Optional[EmailStr]
    phone: Optional[Phone]---------------> HERE
    role:  Optional[RoleType]

我想为电话号码创建一个自定义数据类型......所以我可以在多个地方使用它......我正在尝试如下

class Phone(BaseModel):
    phone: str
    @validator('phone')
    def phone_validation(cls, v):
        phone = v.phone.get("phone")
        logger.debug(f"phone in 2 validator:{v}")
        regex = r"^(\+)[1-9][0-9\-\(\)\.]{9,15}$"
        if v and not re.search(regex, v, re.I):
            raise ValueError("Phone Number Invalid.")
        return v
    class Config:
        orm_mode = True
        use_enum_values = True

通过邮递员,我正在发送

{
    "phone": "+917777777777"
}

我在邮递员中看到 400 错误

[
    {
        "loc": [
            "phone",
            "phone"
        ],
        "msg": "field required",
        "type": "value_error.missing"
    }
]

关于我在上面做错的任何输入

【问题讨论】:

    标签: python sqlalchemy pydantic


    【解决方案1】:

    这不起作用,因为您正在传递:

    {
        "phone": "+917777777777"
    }
    

    而模型的结构为UserPatchEntity.Phone.phone

    为了完成这项工作,我看到了两个选项:

    1。调整 JSON 正文(并修复 validator

    修复validator

    class Phone(BaseModel):
        phone: str
        @validator("phone")
        def phone_validation(cls, v):
            # phone = v.phone.get("phone") #  <-- This line needs to be removed.
            logger.debug(f"phone in 2 validator:{v}")
            regex = r"^(\+)[1-9][0-9\-\(\)\.]{9,15}$"
            if v and not re.search(regex, v, re.I):
                raise ValueError("Phone Number Invalid.")
            return v
    
        class Config:
            orm_mode = True
            use_enum_values = True
    

    改为发送:

    {
      "phone": {
        "phone": "+917777777777"
      }
    }
    

    它现在应该可以工作了。

    2。将validator 移动到父模型

    我认为以下内容更符合您的要求:

    class UserPatchEntity(BaseModel):
        user_id: Optional[UUID]
        first_name: Optional[str] = Field(min_length=1, max_length=32)
        last_name: Optional[str] = Field(min_length=1, max_length=32)
        email: Optional[EmailStr]
        phone: Optional[str]  # <-- This is a str now, everything else stays the same
        role:  Optional[RoleType]
    
        @validator("phone")
        def phone_validation(cls, v):
            logger.debug(f"phone in 2 validator:{v}")
            regex = r"^(\+)[1-9][0-9\-\(\)\.]{9,15}$"
            if v and not re.search(regex, v, re.I):
                raise ValueError("Phone Number Invalid.")
            return v
    
        class Config:
            orm_mode = True
            use_enum_values = True
    

    这样你就可以像你期望的那样在正文中传递phone

    {
        "phone": "+917777777777"
    }
    

    假设您使用的是 FastAPI,在这两种情况下,如果电话号码太短、太长或包含无效字符,您都会收到以下错误:

    {
      "detail": [
        {
          "loc": [
            "body",
            "phone"
          ],
          "msg": "Phone Number Invalid.",
          "type": "value_error"
        }
      ]
    }
    

    注意事项/提示:

    • Pydantic 有一个constr(约束字符串)类型,它允许您定义最小和最大长度,以及其他一些东西。对于 phone 字段,您可以使用以下内容而不是 str,例如:

      class UserPatchEntity(BaseModel):
          ...
          phone: Optional[
              constr(
                  strip_whitespace=True,
                  min_length=9,
                  max_length=15,
              )
          ]
      

      它还允许您直接指定regex 字符串,例如:

      class UserPatchEntity(BaseModel):
          ...
          phone: Optional[
              constr(
                  strip_whitespace=True,
                  regex=r"^(\+)[1-9][0-9\-\(\)\.]{9,15}$",
              )
          ]
      

      这样可以省去你写明确的validator

    • 如果你继续“直接”使用正则表达式,我会建议 compile() 他们让他们更快一点。

    • 假设您使用的是 FastAPI,您可以在应用程序运行时导航到 http://localhost:8000/docs,在那里您会找到完整的 OpenAPI 接口。您可以直接从那里发送有效负载,它还会向您显示每个端点的签名。在第一种情况下,如果您这样定义端点:

      @router.post("/user/")
      async def post_user(user_patch_entity: UserPatchEntity):
          return user_patch_entity.phone
      

      它会显示这样的文档:

    【讨论】:

      猜你喜欢
      • 2020-05-13
      • 1970-01-01
      • 2022-11-26
      • 2014-12-20
      • 2021-11-25
      • 1970-01-01
      • 2010-12-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多