SqlAlchemy如何处理表定义中的唯一约束

时间:2011-04-20 11:30:39

标签: sqlalchemy unique

我有一个包含以下声明性定义的表:

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的条目? 如果没有,我应该在内存中保留所有现有名称,以便在创建对象之前检查它们是否存在吗?

4 个答案:

答案 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)

From the docs

class MyClass(Base):
    __tablename__ = 'sometable'
    __table_args__ = (
            ForeignKeyConstraint(['id'], ['remote_table.id']),
            UniqueConstraint('foo'),
            {'autoload':True}
            )

答案 3 :(得分:1)

.one()会抛出两种异常: sqlalchemy.orm.exc.NoResultFoundsqlalchemy.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)