我有下面的mlModel Base Class和表模型,但我无法在保持约束的同时使我的Decimal
字段成为可选的.
PS:我已经知道这个问题已经针对pydantic进行了讨论,但该解决方案似乎不适用于SQlModel.
- 首次try (错误:
ValueError: Unknown constraint max_digits
)
class ItemBase(SQLModel):
# ...
price: Optional[Decimal] = Field(
default=None, max_digits=7, decimal_places=4, ge=0, le=100
)
# ...
class ItemTable(ItemBase, table=True):
__tablename__ = "item"
# ...
- Pydantic解决方案要求仅对December(https://github.com/pydantic/pydantic/discussions/7962#discussioncomment-7939114)应用约束在SQlModel中会产生错误:
TypeError: issubclass() arg 1 must be a class
class ItemBase(SQLModel):
# ...
price: Optional[Annotated[Decimal, Field(
default=None, max_digits=7, decimal_places=4, ge=0, le=100
)]] = None
# ...
- 我让代码发挥作用的解决方案是使用sa_entry来实现
max_digits
和decimal_places
约束,这没关系,因为这在数据库端确实很重要.
class ItemBase(SQLModel):
price: Optional[Decimal] = Field(
default=None, ge=0, le=100, sa_column=Column(DECIMAL(7,4)),
regex=r"^\d+(\.\d+)?$" # added for the string part to only accept numbers
)
通过最后一次try ,le
和ge
约束在Python中正常工作:
ItemTable(..., price=Decimal(123.45)) # => throws ValidationError
ItemTable(..., price=Decimal(34.12)) # => works fine
但现在我的问题是用它生成的json模式放弃了我的所有约束,变成了only:
anyOf: [{type: number}, {type: string}, {type: null}]
有问题,因为我然后使用json模式为我的测试创建假对象(使用jsf库),并且在没有约束的情况下,我的测试都会失败.
Edit with an answer:
感谢@Jeremy,我认为第2点中所述的错误仅发生在table=True
个模型上.所以我最终做了以下操作:
class ItemBase(SQLModel):
# ...
price: Optional[Annotated[Decimal, Field(
multiple_of=0.0001, ge=0, le=100
)]] = None
# ...
class ItemTable(ItemBase, table=True):
price: Optional[Decimal] = Field(
default=None, ge=0, le=100, sa_column=Column(DECIMAL(7,4)
)
为了将模式约束添加到小数json模型的字符串类型中,我必须将pydantic的GenerateJsonSchema
子类化:
class MySchemaGenerator(GenerateJsonSchema):
def decimal_schema(self, schema: core_schema.DecimalSchema) -> JsonSchemaValue:
json_schema = self.str_schema(core_schema.str_schema(pattern=r"^[-+]?\d+((?:\.\d+)|(?:[eE][-+]?\d+))?$"))
... # the rest of the method is unchanged
ItemBase.model_json_schema(schema_generator=MySchemaGenerator)
"""returns for 'price' property:
{'price': {'anyOf': [{'maximum': 100.0,
'minimum': 0.0,
'multipleOf': 0.0001,
'type': 'number'},
{'pattern': '^[-+]?\\d+((?:\\.\\d+)|(?:[eE][-+]?\\d+))?$',
'type': 'string'},
{'type': 'null'}],
'default': None,
'title': 'Price'}
"""
但这样我就不能直接在字段上指定模式,因此所有小数都将具有相同的模式.如果有人知道如何将regex从字段定义传递到decimal_schema
方法,我很乐意接受它!