SQLAlchemy默认值重复问题:如何让UUID列每次生成新值?
问题:SQLAlchemy中UUID默认值重复,如何实现每次插入自动生成新UUID?
在SQLAlchemy的declarative_base子类中定义了一个默认值为uuid4的列,但运行脚本时,每次插入的UUID都会沿用同一个值。需要实现每次插入数据时自动生成新的UUID作为该列的默认值。
错误代码示例
import os import uuid from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy import Column, Integer, String from sqlalchemy.orm import declarative_base Base = declarative_base() class Test(Base): __tablename__ = "test" id = Column(Integer, autoincrement=True, primary_key=True) msg = Column(String(100), nullable=False) # 错误:类定义时就执行了uuid.uuid4().hex,生成固定值 uuid = Column(String(32), default=uuid.uuid4().hex, nullable=True) engine = create_engine( os.getenv('SQLALCHEMY_DATABASE_URI'), echo=True ) Session = sessionmaker(bind=engine) for x in range(2): model = Test(msg=f"Hey! - {x}") with Session() as session: session.add(model) session.commit() session.close()
实际输出(Echo日志)
2022-10-10 14:42:44,963 INFO sqlalchemy.engine.Engine SELECT CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR) 2022-10-10 14:42:44,963 INFO sqlalchemy.engine.Engine [raw sql] () 2022-10-10 14:42:45,005 INFO sqlalchemy.engine.Engine SELECT schema_name() 2022-10-10 14:42:45,005 INFO sqlalchemy.engine.Engine [generated in 0.00022s] () 2022-10-10 14:42:45,081 INFO sqlalchemy.engine.Engine SELECT CAST('test max support' AS NVARCHAR(max)) 2022-10-10 14:42:45,081 INFO sqlalchemy.engine.Engine [generated in 0.00032s] () 2022-10-10 14:42:45,202 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2022-10-10 14:42:45,204 INFO sqlalchemy.engine.Engine INSERT INTO test (msg, uuid) OUTPUT inserted.id VALUES (?, ?) 2022-10-10 14:42:45,204 INFO sqlalchemy.engine.Engine [generated in 0.00020s] ('Hey! - 0', '58a2f6d418a9428b92c0b81ad81c4585') 2022-10-10 14:42:45,311 INFO sqlalchemy.engine.Engine COMMIT 2022-10-10 14:42:45,371 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2022-10-10 14:42:45,371 INFO sqlalchemy.engine.Engine INSERT INTO test (msg, uuid) OUTPUT inserted.id VALUES (?, ?) 2022-10-10 14:42:45,371 INFO sqlalchemy.engine.Engine [cached since 0.1675s ago] ('Hey! - 1', '58a2f6d418a9428b92c0b81ad81c4585') 2022-10-10 14:42:45,478 INFO sqlalchemy.engine.Engine COMMIT
期望输出(Echo日志)
2022-10-10 14:56:18,458 INFO sqlalchemy.engine.Engine SELECT CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR) 2022-10-10 14:56:18,458 INFO sqlalchemy.engine.Engine [raw sql] () 2022-10-10 14:56:18,518 INFO sqlalchemy.engine.Engine SELECT schema_name() 2022-10-10 14:56:18,519 INFO sqlalchemy.engine.Engine [generated in 0.00022s] () 2022-10-10 14:56:18,599 INFO sqlalchemy.engine.Engine SELECT CAST('test max support' AS NVARCHAR(max)) 2022-10-10 14:56:18,599 INFO sqlalchemy.engine.Engine [generated in 0.00018s] () 2022-10-10 14:56:18,704 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2022-10-10 14:56:18,706 INFO sqlalchemy.engine.Engine INSERT INTO test (msg, uuid) OUTPUT inserted.id VALUES (?, ?) 2022-10-10 14:56:18,706 INFO sqlalchemy.engine.Engine [generated in 0.00019s] ('Hey! - 0', '58a2f6d418a9428b92c0b81ad81c4585') 2022-10-10 14:56:18,846 INFO sqlalchemy.engine.Engine COMMIT 2022-10-10 14:56:18,862 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2022-10-10 14:56:18,862 INFO sqlalchemy.engine.Engine INSERT INTO test (msg, uuid) OUTPUT inserted.id VALUES (?, ?) 2022-10-10 14:56:18,863 INFO sqlalchemy.engine.Engine [cached since 0.1569s ago] ('Hey! - 1', '13f37ce5a48c44bbaa0c883f2f35da3d') 2022-10-10 14:56:18,929 INFO sqlalchemy.engine.Engine COMMIT
解决方案
问题原因
代码中default=uuid.uuid4().hex是在类定义阶段就执行了uuid.uuid4().hex,生成了一个固定的字符串,之后所有创建的Test实例都会复用这个固定值,导致UUID重复。
SQLAlchemy的default参数需要接收可调用对象(比如函数或lambda),而不是直接传递函数执行的结果,这样每次创建实例时才会调用该对象生成新值。
修改后的代码
将UUID列的default值改为lambda函数,每次创建实例时都会调用该lambda生成新的UUID hex字符串:
import os import uuid from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy import Column, Integer, String from sqlalchemy.orm import declarative_base Base = declarative_base() class Test(Base): __tablename__ = "test" id = Column(Integer, autoincrement=True, primary_key=True) msg = Column(String(100), nullable=False) # 正确:传递lambda函数,每次创建实例时执行生成新的UUID hex uuid = Column(String(32), default=lambda: uuid.uuid4().hex, nullable=True) engine = create_engine( os.getenv('SQLALCHEMY_DATABASE_URI'), echo=True ) Session = sessionmaker(bind=engine) for x in range(2): model = Test(msg=f"Hey! - {x}") with Session() as session: session.add(model) session.commit() session.close()
另一种实现方式
如果希望将UUID的生成逻辑封装成独立函数,也可以直接传递函数名(注意不要加括号,否则会立即执行):
def generate_uuid(): return uuid.uuid4().hex # 在列定义中使用: uuid = Column(String(32), default=generate_uuid, nullable=True)
这样每次创建Test实例时,SQLAlchemy都会调用generate_uuid()生成新的UUID值,满足需求。
内容的提问来源于stack exchange,提问作者MertG
相关产品推荐
相关产品推荐

