gpt4 book ai didi

python - 使用 SQLAlchemy 关联代理强制唯一性

转载 作者:搜寻专家 更新时间:2023-10-30 20:26:39 24 4
gpt4 key购买 nike

我正在尝试使用关联代理来简化标记样式记录的处理,但我遇到了强制唯一性和让对象重用现有标记而不是始终创建新标记的问题。

这是一个类似于我的设置。文档中的示例有一些 enforcing uniqueness 的配方,但它们都依赖于对 session 的访问权限,并且通常需要一个单一的全局 session ,而我无法做到这一点。

from sqlalchemy import Column, Integer, String, create_engine, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy

Base = declarative_base()
engine = create_engine('sqlite://', echo=True)
Session = sessionmaker(bind=engine)


def _tag_find_or_create(name):
# can't use global objects here, may be multiple sessions and engines
# ?? No access to session here, how to do a query
tag = session.query(Tag).filter_by(name=name).first()
tag = Tag.query.filter_by(name=name).first()
if not tag:
tag = Tag(name=name)
return tag


class Item(Base)
__tablename__ = 'item'

id = Column(Integer, primary_key=True)
tags = relationship('Tag', secondary='itemtag')
tagnames = association_proxy('tags', 'name', creator=_tag_find_or_create)


class ItemTag(Base)
__tablename__ = 'itemtag'

id = Column(Integer, primary_key=True)
item_id = Column(Integer, ForeignKey('item.id'))
tag_id = Column(Integer, ForeignKey('tag.id'))


class Tag(Base)
__tablename__ = 'tag'

id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)


# Scenario 1
session = Session()
item = Item()
session.add(item)
item.tagnames.append('red')

# Scenario 2
item2 = Item()
item2.tagnames.append('blue')
item2.tagnames.append('red')
session.add(item2)

如果没有 creator 函数,我只会得到大量重复的标签项。 creator 函数似乎是放置此类检查的最明显位置,但我不确定如何从 creator 函数内部进行查询。

考虑示例底部提供的两个场景。在第一个示例中,似乎应该有一种方法可以在 creator 函数中访问 session ,因为要添加标签的对象已经与 session 相关联。

在第二个示例中,Item 对象尚未与 session 关联,因此无法在 creator 函数中进行验证检查。它必须稍后在对象实际添加到 session 时发生。

对于第一种情况,我将如何访问 creator 函数中的 session 对象?

对于第二种情况,是否有办法“监听”父对象何时添加到 session 并在此时验证关联代理?

最佳答案

对于第一种情况,您可以使用object_session .

至于总体问题:是的,您需要访问当前 session ;如果在您的应用程序中使用 scoped_session 是合适的,那么您链接到的食谱的第二部分应该可以正常使用。参见 Contextual/Thread-local Sessions了解更多信息。

在事件从 transient 变为持久 状态时处理事件和更改对象不会使您的代码漂亮或非常健壮。所以我会立即将新的 Tag 对象添加到 session 中,如果事务被回滚,它们将不在数据库中。

请注意,在多用户环境中,您可能会遇到竞争条件:同一个标签是新的,并且由两个用户同时创建。最后提交的用户将失败(如果您对数据库有唯一约束)。在这种情况下,您可能会考虑没有唯一约束,并且有一个(每日)程序来清理这些重复项(并重新分配关系)。随着时间的推移,新项目会越来越少,发生此类冲突的可能性也越来越小。

关于python - 使用 SQLAlchemy 关联代理强制唯一性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30745064/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com