【问题标题】:Can not update entries with many to many relation in Flask无法在 Flask 中更新具有多对多关系的条目
【发布时间】:2013-09-02 23:20:05
【问题描述】:

我对烧瓶和 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,)) 

我很困惑

【问题讨论】:

    标签: python flask wtforms


    【解决方案1】:

    为什么

    db.session.remove()
    

    在您的代码中?

    sqlalchemy 的快速经验法则:

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

    所以要添加一个新类别,您只需

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

    修改类别

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

    删除关联

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

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

    • db.session.delete(cat)

    【讨论】:

    • 感谢您的回复。正如我上面所说,没有 db.session.remove() 我还有另一个错误 InvalidRequestError。我可以创建新帖子、新类别、编辑帖子的其他字段,但不能将现有类别附加到任何现有帖子。我猜这个问题在代码更深的地方,而不仅仅是我发布的部分
    【解决方案2】:

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

    【讨论】:

    • 是的,这是使用 flask_whooshalchemy 库时的问题。 Miguel Grinberg 的补丁(上面答案中的链接)最终被合并到库的 github 存储库中。但截至 2014 年 5 月,它尚未发布到 pip。如果您需要克服此错误,您需要手动将补丁应用到 f​​lask_whooshalchemy.py。
    猜你喜欢
    • 2021-09-15
    • 1970-01-01
    • 2021-07-10
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 2015-08-25
    • 2018-07-28
    相关资源
    最近更新 更多