为什么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字符串的小实用程序函数,并返回现有标签或为您创建一个新标签。

回答:

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

尝试做这样的事情:

e.tags.append(u"bar") 

而不是

e.tags = ... 

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

以上是 为什么SQLAlchemy/associationproxy复制我的标签? 的全部内容, 来源链接: utcz.com/qa/263926.html

回到顶部