我有一个包含以下声明性定义的表:
class Type(Base):
__tablename__ = 'Type'
id = Column(Integer, primary_key=True)
name = Column(String, unique = True)
def __init__(self, name):
self.name = name
“name”列有一个唯一的约束,但我能够做到
type1 = Type('name1')
session.add(type1)
type2 = Type(type1.name)
session.add(type2)
因此,可以看出,根本没有检查唯一约束,因为我已经在会话中添加了2个具有相同名称的对象。
当我session.commit()
时,我得到一个mysql错误,因为约束也在mysql表中。
sqlalchemy是否有可能提前告诉我,我无法制作或识别它,并且不会插入两个具有相同“名称”columm的条目? 如果没有,我应该在内存中保留所有现有名称,以便在创建对象之前检查它们是否存在吗?
答案 0 :(得分:9)
SQLAlechemy不处理uniquness,因为它不可能做得很好。即使您跟踪创建的对象和/或检查是否存在具有此类名称的对象,也存在竞争条件:其他进程中的任何人都可以使用您刚检查的名称插入新对象。唯一的解决方案是在检查之前锁定整个表并在插入后释放锁(某些数据库支持这种锁定)。
答案 1 :(得分:6)
AFAIK,sqlalchemy不处理python行为中的唯一性约束。那些“unique = True”声明仅用于强加数据库级表约束,并且只有在使用sqlalchemy命令创建表时才会使用,即
Type.__table__.create(engine)
或其他一些。如果针对实际上不存在此约束的现有表创建SA模型,则它就好像它不存在一样。
根据您的具体用例,您可能需要使用类似
的模式try:
existing = session.query(Type).filter_by(name='name1').one()
# do something with existing
except:
newobj = Type('name1')
session.add(newobj)
或变体,或者您只需捕获mysql异常并从那里恢复。
答案 2 :(得分:3)
class MyClass(Base):
__tablename__ = 'sometable'
__table_args__ = (
ForeignKeyConstraint(['id'], ['remote_table.id']),
UniqueConstraint('foo'),
{'autoload':True}
)
答案 3 :(得分:1)
.one()
会抛出两种异常:
sqlalchemy.orm.exc.NoResultFound
和sqlalchemy.orm.exc.MultipleResultsFound
你应该在第一个异常发生的时候创建那个对象,如果第二个异常发生你仍然被搞砸了,不应该做得更糟。
try:
existing = session.query(Type).filter_by(name='name1').one()
# do something with existing
except NoResultFound:
newobj = Type('name1')
session.add(newobj)