Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用SQLAlchemy关联代理强制唯一性_Python_Database_Orm_Sqlalchemy - Fatal编程技术网

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

Python 使用SQLAlchemy关联代理强制唯一性,python,database,orm,sqlalchemy,Python,Database,Orm,Sqlalchemy,我试图使用关联代理来简化标记样式记录的处理,但是我遇到了一个问题:强制唯一性和让对象重用现有标记,而不是总是创建新标记 这是一个类似于我的设置。文档中的示例提供了一些解决方案,但它们都依赖于访问会话,并且通常需要一个全局会话,在我的示例中,我无法做到这一点 从sqlalchemy导入列,整数,字符串,创建引擎,外键 从sqlalchemy.orm导入sessionmaker,关系 从sqlalchemy.ext.declarative导入声明性基础 从sqlalchemy.ext.associa

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

这是一个类似于我的设置。文档中的示例提供了一些解决方案,但它们都依赖于访问会话,并且通常需要一个全局会话,在我的示例中,我无法做到这一点

从sqlalchemy导入列,整数,字符串,创建引擎,外键
从sqlalchemy.orm导入sessionmaker,关系
从sqlalchemy.ext.declarative导入声明性基础
从sqlalchemy.ext.associationproxy导入关联\u proxy
Base=声明性_Base()
引擎=创建引擎('sqlite://',echo=True)
会话=会话生成器(绑定=引擎)
定义标记查找或创建(名称):
#此处无法使用全局对象,可能有多个会话和引擎
# ?? 这里没有访问会话的权限,如何进行查询
tag=session.query(tag).filter_by(name=name).first()
tag=tag.query.filter_by(name=name).first()
如果没有标签:
标记=标记(名称=名称)
返回标签
类别项目(基本)
__tablename_uu='item'
id=列(整数,主键=True)
tags=关系('Tag',secondary='itemtag')
标记名=关联\代理('tags','name',creator=\标记\查找\或\创建)
类ItemTag(基)
__tablename_uu='itemtag'
id=列(整数,主键=True)
item_id=列(整数,ForeignKey('item.id'))
tag_id=列(整数,ForeignKey('tag.id'))
类标记(基)
__tablename_uu='tag'
id=列(整数,主键=True)
name=Column(字符串(50),null=False)
#情景1
会话=会话()
项目=项目()
会话.添加(项目)
item.tagnames.append('red')
#情景2
item2=Item()
item2.tagnames.append('blue')
item2.tagnames.append('red')
会话.添加(项目2)
如果没有creator函数,我只会得到大量重复的标签项。creator函数似乎是放置此类检查的最明显的地方,但我不确定如何从creator函数内部执行查询

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

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

对于第一个场景,我将如何在creator函数中访问会话对象


对于第二个场景,是否有一种方法可以“侦听”父对象添加到会话中的时间,并在该时间点验证关联代理

对于第一个场景,您可以使用

至于整个问题:是的,您需要访问当前会话;如果在应用程序中使用
scoped_session
是合适的,那么您链接到的配方的第二部分应该可以很好地使用。有关更多信息,请参阅

当事件和更改对象从暂时状态更改为持久状态时,处理它们不会使代码变得漂亮或非常健壮。因此,我会立即向会话添加新的
标记
对象,如果事务回滚,它们将不在数据库中

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

如何访问creator函数中的项目对象以使用
object\u会话
?有没有办法告诉关联代理将父对象传递给创建者函数?例如,您可以在
上创建一个helper方法:
def add\u tag(self,tag\u name):object\u session(self)。query(…)…
,在这种情况下,您可以跳过关联代理。使用关联代理,您可以创建自己的子类并拦截修改操作。但实际上,我认为
UniqueObject
recipe应该适合上下文绑定会话。