【问题标题】:How does SqlAlchemy handle unique constraint in table definitionSqlAlchemy 如何处理表定义中的唯一约束
【发布时间】:2011-04-20 11:30:38
【问题描述】:

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

class Type(Base):
    __tablename__ = 'Type'
    id = Column(Integer, primary_key=True)
    name = Column(String, unique = True)
    def __init__(self, name):
        self.name = name

“名称”列具有唯一约束,但我可以做到

type1 = Type('name1')
session.add(type1)
type2 = Type(type1.name)
session.add(type2)

因此,可以看出,唯一约束根本没有被检查,因为我已将 2 个具有相同名称的对象添加到会话中。

当我执行session.commit() 时,我得到一个 mysql 错误,因为约束也在 mysql 表中。

sqlalchemy 是否有可能提前告诉我我无法制作或识别它并且不插入具有相同“名称”列的 2 个条目? 如果没有,我是否应该将所有现有名称保留在内存中,以便在创建对象之前检查它们是否存在?

【问题讨论】:

    标签: sqlalchemy unique


    【解决方案1】:

    SQLAlechemy 不处理唯一性,因为它不可能做好事。即使您跟踪创建的对象和/或检查是否存在具有该名称的对象,也存在竞争条件:其他进程中的任何人都可以插入具有您刚刚检查的名称的新对象。唯一的解决办法是在检查前锁定整个表,插入后释放锁定(有些数据库支持这种锁定)。

    【讨论】:

    • 我将是唯一一个在那里插入数据的人,所以我会确保不会发生这种情况。我的问题是关于 sqlalchemy 如何处理字段的唯一性
    • @duduklein 它不处理唯一性。我的回答说明了原因。
    【解决方案2】:

    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 异常并从那里恢复。

    【讨论】:

      【解决方案3】:

      From the docs

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

      【讨论】:

      • 这与使用原始问题中的unique=True 有什么不同?
      • unique=True 没有机会为索引指定唯一名称,这将导致 alembic 出现问题。见:alembic.sqlalchemy.org/en/latest/naming.html
      • 好的,但这是否回答了最初的问题?我认为对您与 OP 问题的关系进行更多解释可能会有所帮助。
      • 不确定,但这个问题已经有将近十年的历史了,这不是公认的答案。
      • 这并不意味着它仍然不经常被发现。我只是想了解您的答案并解释我的-1。
      【解决方案4】:

      .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)
      

      【讨论】:

        猜你喜欢
        • 2015-09-19
        • 1970-01-01
        • 1970-01-01
        • 2016-08-22
        • 2022-10-05
        • 1970-01-01
        • 2016-02-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多