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

发布于 2024-11-02 14:42:12 字数 585 浏览 4 评论 0原文

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

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

I have a table with the following declarative definition:

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

The column "name" has a unique constraint, but I'm able to do

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

So, as can be seen, the unique constraint is not checked at all, since I have added to the session 2 objects with the same name.

When I do session.commit(), I get a mysql error since the constraint is also in the mysql table.

Is it possible that sqlalchemy tells me in advance that I can not make it or identifies it and does not insert 2 entries with the same "name" columm?
If not, should I keep in memory all existing names, so I can check if they exist of not, before creating the object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北音执念 2024-11-09 14:42:12

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

SQLAlechemy doesn't handle uniquness, because it's not possible to do good way. Even if you keep track of created objects and/or check whether object with such name exists there is a race condition: anybody in other process can insert a new object with the name you just checked. The only solution is to lock whole table before check and release the lock after insertion (some databases support such locking).

笔芯 2024-11-09 14:42:12

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

AFAIK, sqlalchemy does not handle uniqueness constraints in python behavior. Those "unique=True" declarations are only used to impose database level table constraints, and only then if you create the table using a sqlalchemy command, i.e.

Type.__table__.create(engine)

or some such. If you create an SA model against an existing table that does not actually have this constraint present, it will be as if it does not exist.

Depending on your specific use case, you'll probably have to use a pattern like

try:
  existing = session.query(Type).filter_by(name='name1').one()
  # do something with existing
except:
  newobj = Type('name1')
  session.add(newobj)

or a variant, or you'll just have to catch the mysql exception and recover from there.

勿挽旧人 2024-11-09 14:42:12

来自文档

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

From the docs

class MyClass(Base):
    __tablename__ = 'sometable'
    __table_args__ = (
            ForeignKeyConstraint(['id'], ['remote_table.id']),
            UniqueConstraint('foo'),
            {'autoload':True}
            )
無心 2024-11-09 14:42:12

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

.one() throws two kinds of exceptions:
sqlalchemy.orm.exc.NoResultFound and sqlalchemy.orm.exc.MultipleResultsFound

You should create that object when the first exception occurs, if the second occurs you're screwed anyway and shouldn't make is worse.

try:
  existing = session.query(Type).filter_by(name='name1').one()
# do something with existing
except NoResultFound:
  newobj = Type('name1')
  session.add(newobj)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文