我对flask和sqlalchemy全新。我尝试建立一个网站只是为了更好地了解烧瓶。我有博客,用户可以创建帖子和设置多个标签。我使用flask-sqlalchemy和wtforms-alchemy。我有2个型号
association_table = db.Table('association',
db.Column('post_id', db.Integer, db.ForeignKey('post.id')),
db.Column('category_id', db.Integer, db.ForeignKey('category.id'))
)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
body = db.Column(db.Text, nullable=False)
pub_date = db.Column(db.DateTime)
categories = db.relationship('Category', secondary=association_table,
backref=db.backref('posts', lazy='dynamic'))
...
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
...
我可以使用下一个视图创建新帖子
def add():
form = PostForm(request.form)
if request.method == 'POST' and form.validate():
post = Post(form.title.data, form.body.data)
db.session.add(post)
tags = form.tags.data.split(',')
for tag in tags:
category = Category.query.filter_by(name=tag.strip()).first()
if not category:
category = Category(tag.strip())
post.categories.append(category)
db.session.commit()
return redirect(...)
return render_template(...)
这应该是有效的。但是我在编辑帖子时遇到了一些问题。当我更改标题或正文时,我必须使用db.session.merge(post),否则它不想保存数据库中的更改。但是在所有教程中都没有合并方法。 第二个问题是我无法更新帖子的标签。我可以创建一个新标签并将其添加到某个帖子中。但是,如果我尝试将现有标签添加到任何帖子我都有错误。
AssertionError: A conflicting state is already present in the identity map for key (<class 'db.models.Category'>, (1,))
我的观点看起来像
def edit(post_id):
post = Post.query.get(post_id)
form = PostForm(request.form, post)
if request.method == 'POST' and form.validate():
...
tags = form.tags.data.split(',')
for tag in tags:
category = Category.query.filter_by(name=tag.strip()).first()
if not category:
category = Category(tag.strip())
db.session.remove()
post.categories.append(category)
form.populate_obj(post)
db.session.merge(post)
db.session.commit()
return redirect(...)
else:
...
return render_template(...)
此外,如果我不使用db.session.remove(),我将收到另一个错误
InvalidRequestError: Object '<Category at 0x7f9de40c0d90>' is already attached to session '6' (this is '1')
我哪里错了?谢谢你的帮助!
一次更新。只是为了测试。如果我从一个帖子迭代标签列表,我可以删除这些标签并将其追加。
tags = list(post.categories)
for tag in tags:
post.categories.remove(tag)
for tag in tags:
post.categories.append(tag)
但是如果我删除标签然后从db获取标签并尝试追加 - 得到错误
tags = list(post.categories)
for tag in tags:
post.categories.remove(tag)
for tag in tags:
category = Category.query.filter_by(name=tag.name).first()
post.categories.append(tag)
AssertionError: A conflicting state is already present in the identity map for key (<class 'db.models.Category'>, (1,))
我很困惑
答案 0 :(得分:3)
为什么
db.session.remove()
你的代码中有吗?
sqlalchemy
的快速经验法则:
只有在创建新实例时,才必须将其添加到会话中。 查询返回的所有内容(对关系也有效)已经在会话中,因此您无需添加或删除任何内容。
所以要添加一个新类别,你只需
categories
列表db.session.commit
修改类别
categories
条目db.session.commit
删除关联
categories
列表中删除db.session.commit
要删除类别对象,您还需要
db.session.delete(cat)
答案 1 :(得分:1)
我发现了问题。我使用WooshAlchemy进行文本搜索。它会创建不同的会话。关于这一点的大文章可以找到here