Skip to content

Conversation

go9sky
Copy link
Contributor

@go9sky go9sky commented Sep 2, 2025

原有的 NotBlank 装饰器会始终执行其验证逻辑,这使其不适用于那些“字段可选,但一旦提供就不能为空”的验证场景。

本次提交通过引入一个新的布尔参数 allow_optional 来增强此装饰器。

  • allow_optional 的默认值为 False,这确保了完全的向后兼容性。所有现有的装饰器用法无需任何修改即可正常工作。

  • allow_optional 设置为 True 时,装饰器将仅在该字段被显式提供(即存在于 Pydantic 模型的 model_fields_set 中)时,才执行非空验证。

此次变更极大地提高了该装饰器的通用性和灵活性,使其能覆盖更多的验证场景,并减少了为可选字段编写自定义验证逻辑或独立装饰器的需要。

可选字段使用示例:
@notblank(field_name='nickname', allow_optional=True)

The original `NotBlank` decorator always performed its validation check, making it unsuitable for fields that are optional but must not be empty if provided.

This commit enhances the decorator by introducing a new boolean parameter, `allow_optional`.

- By default, `allow_optional` is `False`, ensuring full backward compatibility with all existing usages. No changes are needed for validating required fields.

- When `allow_optional` is set to `True`, the decorator will only perform the non-blank validation if the field is explicitly included in the Pydantic model's input data (i.e., present in `model_fields_set`).

This change significantly increases the versatility of the decorator, allowing it to cover more validation scenarios and reducing the need for custom logic or separate decorators for optional fields.

Example usage for an optional field:
@notblank(field_name='nickname', allow_optional=True)
@insistence
Copy link
Owner

具体的使用场景是什么,现在的设计逻辑本身就是手动控制的

@go9sky
Copy link
Contributor Author

go9sky commented Sep 5, 2025

用于支持更新指定字段,不指定的字段不更新。

举例

比如,对于数据库,name 非必填,code 必填(无默认值)。那么更新操作时,所有字段都是可选的,必填字段 code 可以不传,但如果传了,那么必须不为空。

具体更新操作传参示例:

  • {} :合法,不会执行更新。
  • {"name": null}:合法,更新 namenull
  • {"code": null}不合法code 不能为空。
  • {"name": "hello", "code": "world"}:合法,更新 name'hello',更新 code'world'
  • {"name": "", "code": ""}不合法code 不能为空。

对于这种设计场景,就需要用到 NotBlank 装饰器新的参数,在 update 数据模型中允许 code 字段可选,但若设置了,则不能设置为空:

class CreateModel(BaseModel):
    """创建操作的数据模型"""    
    name: Optional[str] = Field(default=None, description="名称")
    code: str = Field(..., description="编码")

    @NotBlank(field_name='code', message='编码不能为空')
    def get_code(self):
        return self.code

    def validate_custom_fields(self):
        self.get_code()    


class UpdateModel(BaseModel):
    """更新操作的数据模型"""
    name: Optional[str] = Field(default=None, description="名称")
    code: Optional[str] = Field(default=None, description="编码")

    @NotBlank(field_name='code', allow_optional=True, message='编码不能为空')
    def get_code(self):
        return self.code

    def validate_custom_fields(self):
        self.get_code()    


data = UpdateModel(name=None)
data.validate_custom_fields()
print(data.model_dump(exclude_unset=True))  # 输出:{'name': None}

data2 = CreateModel(code='') 
data2.validate_custom_fields()  # FieldValidationError 校验不通过,编码不能为空

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants