为什么SQLAlchemy/associationproxy复制我的标签?

问题描述:

我试图在与the example in the docs非常类似的情况下使用关联代理的标记。这里是我的架构(这是一个博客)的一个子集,使用声明:为什么SQLAlchemy/associationproxy复制我的标签?

class Tag(Base): 
    __tablename__ = 'tags' 
    id   = Column(Integer, primary_key=True) 
    tag   = Column(Unicode(255), unique=True, nullable=False) 

class EntryTag(Base): 
    __tablename__ = 'entrytags' 
    entry_id  = Column(Integer, ForeignKey('entries.id'), key='entry', primary_key=True) 
    tag_id  = Column(Integer, ForeignKey('tags.id'), key='tag', primary_key=True) 

class Entry(Base): 
    __tablename__ = 'entries' 
    id   = Column(Integer, primary_key=True) 
    subject  = Column(Unicode(255), nullable=False) 
    # some other fields here 
    _tags   = relation('Tag', backref='entries', secondary=EntryTag.__table__) 
    tags   = association_proxy('_tags','tag') 

以下是我想要使用它:

>>> e = db.query(Entry).first() 
>>> e.tags 
[u'foo'] 
>>> e.tags = [u'foo', u'bar'] # really this is from a comma-separated input 
db.commit() 
Traceback (most recent call last): 
[...] 
sqlalchemy.exc.IntegrityError: (IntegrityError) duplicate key value violates unique constraint "tags_tag_key" 
'INSERT INTO tags (id, tag) VALUES (%(id)s, %(tag)s)' {'tag': 'bar', 'id': 11L} 
>>> map(lambda t:(t.id,t.tag), db.query(Tag).all()) 
[(1, u'foo'), (2, u'bar'), (3, u'baz')] 

ID为2已经存在的标签u'bar';为什么SQLAlchemy没有附加那个而不是试图创建它呢?某种程度上我的模式错了吗?

声明:自从我使用SQLAlchemy以来,这已经过时了,所以这比任何事情都更值得猜测。

看起来您期待SQLAlchemy在多对多表上执行插入操作时神奇地取出字符串“bar”并查找相关标签。我期望这是无效的,因为有问题的字段('标记')不是主键。

想象一下类似的情况,其中你的标签表实际上是评论,也有一个ID和一个文本字段。您希望能够使用上面使用的相同的e.comments = ['u'Foo','u'Bar']语法将条目添加到条目中,但您希望它只执行插入,而不是检查具有相同内容的现有评论。

所以这可能是它在这里做的事情,但它会触及标签名称的唯一性约束并失败,假设您尝试做错误的事情。

如何解决?尽管我不知道SQLAlchemy如何有效地处理它,但是使用tags.tag作为主键可以说是正确的做法。如果没有,请在将它们分配给条目之前,按名称查询Tag对象。您可能需要编写一个带有unicode字符串的小实用程序函数,并返回现有标签或为您创建一个新标签。

+0

那么,我链接的例子似乎暗示它会起作用。至少,对于他们来说,定义这个不错的代理将标签呈现为字符串列表似乎很愚蠢,只能说我应该在使用它之前手动查找标签ID。 他们的例子有一个奇怪的地方,它实际上并没有'Tag.tag'上的唯一约束。也许他们的例子只是以很多重复标签结束,在这一点上,我可能会抛弃“标签”对象,并直接在“EntryTag”中标记标签。但后来我失去了拥有不错的backref'entries'的能力,对吧? – 2009-12-14 11:01:58

+0

其实你是对的。他们甚至把它放在他们的常见问题解答中:http://www.sqlalchemy.org/trac/wiki/FAQ#Istherewayto自动创建一个独特的关键字或其他关键词,而不需要关键词,并且可以在其中包含关键词及其建议的修正:http://www.sqlalchemy。org/trac/wiki/UsageRecipes/UniqueObject – 2009-12-14 13:28:34

+0

看着它,我同意他们的例子是不明确的,因为你可能合理地期望相同的关键字解析为相同的实例。如果他们选择了第二张表格而不是唯一性的建议,会更好。 – Kylotan 2009-12-15 01:11:16

我从来没有使用SQLAlchemy的0.5,但(我用最后的应用程序是基于0.4),但我可以看到你的代码一个怪癖:你应该修改的association_proxy对象,而不是重新分配它。

尝试做这样的事情:

e.tags.append(u"bar") 

而不是

e.tags = ... 

如果还是不行,请尝试粘贴一个完整的工作示例为那些表(!(包括进口),请)和我会给你更多的建议。

+0

好想,但是'append'给出了相同的结果(提交时重复键)。当我不在工作时,将完成这个例子(这不是一个工作项目)。 – 2009-12-14 10:53:11