python - 如何在声明中指定时自动验证字符串/Unicode 列的最大长度?
问题描述
String
SQLAlchemy 允许在声明列时指定长度:
foo = Column(String(10))
如在 SQL 中:
foo VARCHAR(10)
我知道某些 DBMS 使用此长度值在表中创建行时分配内存。但是一些 DBMS(如 SQLite)并不关心它,并且只为了与 SQL 标准兼容而接受这种语法。但是一些 DBMS(如 MySQL)需要指定它。
就个人而言,我喜欢为某些文本数据指定最大长度,因为它有助于设计 UI,因为您知道显示它所需的区域。
此外,我认为这将使我的应用程序行为在不同的 DBMS 中更加一致。
因此,我想通过检查其长度与声明的长度(当声明长度时)来验证插入时字符串/Unicode 列的值。
检查约束
第一个解决方案是使用检查约束:
from sqlalchemy import CheckConstraint, Column, Integer, String, create_engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine("sqlite:///:memory:", echo=True)
Base = declarative_base(bind=engine)
Session = sessionmaker(bind=engine)
class Foo(Base):
__tablename__ = "Foo"
id = Column(Integer, primary_key=True)
bar = Column(String(10), CheckConstraint("LENGTH(bar) < 10"))
Base.metadata.create_all()
if __name__ == "__main__":
session = Session()
session.add(Foo(bar="a" * 20))
try:
session.commit()
except IntegrityError as e:
print(f"Failed with: {e.orig}")
它可以工作,但 SQLAlchemy 不会生成 SQL约束表达式。因此,如果 DBMS 需要不同的语法,它可能需要一些自定义生成。
验证器
我还尝试使用 SQLAlchemy验证器:
class Foo(Base):
__tablename__ = "Foo"
id = Column(Integer, primary_key=True)
bar = Column(String(10))
@validates("bar")
def check_bar_length(self, key, value):
column_type = getattr(type(self), key).expression.type
max_length = column_type.length
if len(value) > max_length:
raise ValueError(
f"Value '{value}' for column '{key}' "
f"exceed maximum length of '{max_length}'"
)
return value
try:
Foo(bar="a" * 20)
except ValueError as e:
print(f"Failed with: {e}")
现在,最大长度是从声明的长度中推断出来的。
检查是在实体创建时完成的,而不是在提交时完成的。我不知道这是否可能是一个问题。
自定义类型
上面显示的两种解决方案都需要对每一列应用验证。我正在寻找一种解决方案来自动检查具有声明长度的字符串/Unicode 列。
使用自定义类型可能是解决方案。但它看起来像一个丑陋的 hack,因为自定义类型不是用于数据验证,而是用于数据转换。
那么,您是否考虑过另一种解决方案,也许是我不知道的 SQLAlchemy 功能,它将帮助我将检查自动添加到指定String
a 的所有列中length
?
解决方案
Another option might be to explicitly define the table and factor out your string column definitions so the check constraint is made for every string column without needing to repeat it.
def string_column(name, length):
check_str = "LENGTH({}) < {}".format(name, length)
return Column(name, String(length), CheckConstraint(check_str))
class Foo(Base):
__table__ = Table("Foo", Base.metadata,
Column("id", Integer, primary_key=True),
string_column("bar", 10),
string_column("name", 15))
推荐阅读
- google-kubernetes-engine - 可以将 GKE 多专区集群迁移到单专区集群吗?
- javascript - 用于 Javascript 的类似 SQL 的内部联接
- vb.net - 以 DataTable 作为 DataSource 的 DataGridView 中未显示数据
- javascript - JPlayer 设置自定义持续时间
- azure - 是否可以为 ASE 中托管的端点(AppService)配置 ApplicationInsights 的 AvailabilityTests?
- python - 为什么数据框 df < 1 对于包含单个 str 值的任何列都返回 True ?
- react-native - React Navigation:动态隐藏标题
- powershell - 运行硬件清单脚本时出现 Powershell 错误
- php - 在 Nginx 上部署 laravel
- sql-server - SSRS - 按单个 tablix 列排序导致列组