对 SQLAlchemy 中的 UniqueKeyViolation 做出反应

发布于 2024-11-30 07:10:25 字数 1521 浏览 1 评论 0原文

我在 SQLAlchemy 中有 2 个表(使用 declerative_base()),它们通过单独的表关系连接起来

# no comment on the wired naming....
site_word = Table('word_site', Base.metadata,
    Column('site_id', Integer, ForeignKey('sites.site_id'), nullable = False, primary_key = True),
    Column('word_id', Integer, ForeignKey('site_words.word_id'), nullable = False, primary_key = True))

单词映射

class Word(Base):
   # snip
   word =  Column('word', Text, nullable = False, unique = True)
   sites = relationship('Site', secondary = site_word, back_populates = 'words')

站点映射

class Site(Base):
   # snip
   words = relationship('Word', secondary = site_word, back_populates = 'sites')

插入工作如预期,插入已经存在的单词当然会失败,因为 唯一Word.word 中。

我尝试使用 before_insert 事件来检查该项目是否已存在。

event.listen(Word, 'before_insert', some_event)

我可以获得信息来按预期唯一识别单词,但我不知道如何向连接表 (site_word) 添加新值。

我可以为数据库编写触发器或过程,但不想将太多逻辑移入数据库(不知道这是否可行,因为此时不知道 Site时间)。我可以删除 word 列的约束,但我仍然无法弄清楚如何访问信息(连接的另一端)以在连接表中创建条目,但不能在Word 表。

我正在寻找一种方法site_wordSite 表中创建条目。

更新 1:
我可以将事件附加到 Site,但我看不到获取要插入的站点信息的可能性。是否可以保存站点并随后创建连接关系?

I have 2 Tables in SQLAlchemy (using declerative_base()) that are joined via a seperate Table relationship

# no comment on the wired naming....
site_word = Table('word_site', Base.metadata,
    Column('site_id', Integer, ForeignKey('sites.site_id'), nullable = False, primary_key = True),
    Column('word_id', Integer, ForeignKey('site_words.word_id'), nullable = False, primary_key = True))

Word mapping

class Word(Base):
   # snip
   word =  Column('word', Text, nullable = False, unique = True)
   sites = relationship('Site', secondary = site_word, back_populates = 'words')

Site mapping

class Site(Base):
   # snip
   words = relationship('Word', secondary = site_word, back_populates = 'sites')

Inserting works like expected, inserting of already existing words fails of course due to unique in Word.word.

I tried using a before_insert event to check if the item already exists.

event.listen(Word, 'before_insert', some_event)

I can get the information to identify the word uniquly as expected but I don't know how to add a new value to the join table (site_word).

I could write a trigger or procedure for the database but don't want to move too much logic into the database (don't know if this would be possible since the Site wouldn't be known at that time). I could remove the constraint for the word-column but I still can't figure out how to access the information (the other end of the join) to create an entry in the join table, but not in the Word table.

I am looking for a way to create a entry in the site_word and Site table only.

update 1:
I could attach the event to the Site but I don't see a possibility to get the information of the to-be-inserted Site. Is there a possibility to save the Site and create the join-relation afterwards?

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

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

发布评论

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

评论(2

野侃 2024-12-07 07:10:25

如果没有如何使用对象的示例,就很难看出问题。我认为您正在尝试执行以下操作:

site = Site()
site.words.append(Word('Someword'))
session.add(site)
session.commit()

如果“someword”已经存在,这当然会引发 IntegrityError 。为了解决这个问题,您需要先在数据库中查询该单词,然后再将其添加到网站:

def get_unique_word(session, word):
    try:
        return session.query(Word).filter(Word.word==word).one()
    except sqlalchemy.orm.exc.NoResultFound:
        return Word(word)

site = Site()
site.words.append(get_unique_word(session, 'someword'))
session.add(site)
session.commit()

如果这完全不合理,那么您必须更详细地描述您的问题。

It is difficult to see the problem without an example of how you are working with your objects. I take it you are trying to do something like this:

site = Site()
site.words.append(Word('Someword'))
session.add(site)
session.commit()

This will of course raise an IntegrityError if 'someword' already exists. To get around this, you need to first query the database for the word before adding it to the site:

def get_unique_word(session, word):
    try:
        return session.query(Word).filter(Word.word==word).one()
    except sqlalchemy.orm.exc.NoResultFound:
        return Word(word)

site = Site()
site.words.append(get_unique_word(session, 'someword'))
session.add(site)
session.commit()

If this is completely off base, then you'll have to describe your problem in greater detail.

情绪 2024-12-07 07:10:25

我设法做到了。 Mark Gemmill 的答案让我朝着正确的方向思考。

我需要听 AttributeEvent 而不是 MapperEvent。

event.listen(Site.words, 'append', test_event, retval = True)

然后我可以做类似的事情:

def test_event(target, value, initiator):
    try:
        return session.query(Word).filter(Word.word == value.word.lower()).one()
    except sqlalchemy.orm.exc.NoResultFound:
        return value 

这要么从表中返回现有的单词,要么只是返回需要持久化的映射对象。

I managed to do it. Mark Gemmill's answer got me thinking in the right direction.

I need to listen to an AttributeEvent instead of an MapperEvent.

event.listen(Site.words, 'append', test_event, retval = True)

Then I can do something like:

def test_event(target, value, initiator):
    try:
        return session.query(Word).filter(Word.word == value.word.lower()).one()
    except sqlalchemy.orm.exc.NoResultFound:
        return value 

This either returns the existing word from the table or simply returns the mapped object that needs to be persisted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文