我试图使用关联代理来处理标记式记录更简单一点,但我遇到了一个问题,强制执行唯一性并让对象重用现有标记而不是总是创建新标记。
这是一个类似于我的设置。文档中的示例有一些enforcing uniqueness的配方,但它们都依赖于访问会话,并且通常需要一个全局会话,在我的情况下我不能这样做。
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 函数中的会话对象?
对于第二种情况,是否可以通过" listen" 将父对象添加到会话并在此时验证关联代理?
答案 0 :(得分:2)
对于第一种情况,您可以使用object_session
。
至于整体问题:是的,您需要访问当前会话;如果在您的应用程序中使用scoped_session
是合适的,那么您链接到的食谱的第二部分应该可以正常使用。有关详细信息,请参阅Contextual/Thread-local Sessions。
当事件从 transient 更改为 persistent 状态时处理事件和更改对象将不会使您的代码非常强大或非常强大。所以我会立即向会话中添加新的Tag
对象,如果事务被回滚,它们将不在数据库中。
请注意,在多用户环境中,您可能会遇到竞争条件:相同的标记是新标记,由两个用户同时创建。提交最后一次的用户将失败(如果您对数据库有唯一约束)。 在这种情况下,您可能会考虑没有唯一约束,并且有(每日)过程来清理这些重复项(并重新分配关系)。随着时间的推移,新项目将会越来越少,而且这种冲突的可能性也会减少。