1

我对烧瓶和 sqlalchemy 完全陌生。我尝试制作一个网站只是为了更好地了解烧瓶。我有类似博客的东西,用户可以在其中创建帖子并设置多个标签。我使用烧瓶-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)    

但是如果我删除标签然后从数据库中获取标签并尝试追加 - 得到一个错误

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,)) 

我很困惑

4

2 回答 2

3

为什么

db.session.remove()

在你的代码中?

快速的经验法则sqlalchemy

只有当您创建一个新实例时,您才必须将其添加到会话中。查询返回的所有内容(对关系也有效)已经在会话中,因此您无需添加或删除任何内容。

因此,要添加一个新类别,您只需

  • 创建对象
  • 添加到会话
  • 附加到categories列表
  • db.session.commit

修改类别

  • 修改所需categories条目
  • db.session.commit

删除关联

  • categories列表中删除
  • db.session.commit

要删除类别对象,您还需要

  • db.session.delete(cat)
于 2013-08-26T08:23:20.800 回答
1

我发现了问题。我使用 WooshAlchemy 进行文本搜索。它会创建不同的会话。大文章可以在这里找到

于 2013-08-26T19:51:51.530 回答