Flask-SQLAlchemy:DetachedInstanceError

问题描述 投票:0回答:1

我一直在尝试使用 Flask-SQLAlchemy 创建一个博客。我有两个数据库对象:User 和 Post,它们彼此之间具有双向关系。每当我的主页尝试访问帖子的作者属性时,都会出现以下错误:

sqlalchemy.orm.exc.DetachedInstanceError:父实例未绑定到会话;的延迟加载操作 属性“作者”无法继续(此错误的背景位于: https://sqlalche.me/e/20/bhk3

这就是我设置数据库的方式:

db = SQLAlchemy(model_class=Base, session_options={
    'expire_on_commit': False
})
db.init_app(app)

db.session.expire_on_commit = False

class Post(db.Model):
    id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False)
    author_id: Mapped[int] = mapped_column(Integer, ForeignKey("user.id"))
    author: Mapped["User"] = relationship('User', back_populates="posts")
    date: Mapped[str] = mapped_column(String(250), nullable=False)
    title: Mapped[str] = mapped_column(String(250), nullable=False)
    subtitle: Mapped[str] = mapped_column(String(250), nullable=False)
    body: Mapped[str] = mapped_column(Text, nullable=False)
    image_url: Mapped[str] = mapped_column(String(250), nullable=False)

class User(UserMixin, db.Model):
    id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False)
    email: Mapped[str] = mapped_column(String(100), nullable=False)
    password: Mapped[str] = mapped_column(String(100), nullable=False)
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    posts: Mapped[List["Post"]] = relationship('Post', back_populates="author")

with app.app_context():
    db.create_all()

我的家乡路线呈现最近的帖子:

@app.route("/")
def home():
    logged_in = current_user.is_active
    is_admin = False
    if current_user.is_active:
        is_admin = current_user.id == 1

    with app.app_context():
        posts = db.session.execute(db.select(Post).order_by(Post.id))
        posts = list(posts.scalars())[::-1]

    return render_template("index.html", recent_posts=posts[0:(recent_posts_size)], year=year, logged_in=logged_in, is_admin=is_admin)

这是我主页的 HTML:

{% extends 'components/template.html' %}
{% block web_title %}Rephy's Blog{% endblock %}
{% block style %}
header.masthead {
    background-image: url('static/img/home-bg.jpg')
}
{% endblock %}
{% block title %}Rephy's Blog{% endblock %}
{% block subtitle %}Welcome! Dive into the world of recent computer science breakthroughs, new technologies, and so much more with my blog!{% endblock %}
{% block content %}
<div class="container px-4 px-lg-5">
            <div class="row gx-4 gx-lg-5 justify-content-center">
                <div class="col-md-10 col-lg-8 col-xl-7">
                    <!-- Post preview-->
                    {% for post in recent_posts %}
                    <div class="post-preview">
                        <a href="{{ url_for('post', id=post.id) }}">
                            <h2 class="post-title">{{ post.title }}</h2>
                            <h3 class="post-subtitle">{{ post.subtitle }}</h3>
                        </a>
                        <p class="post-meta">
                            Posted by
                            <a href="#!">{{ post.author }}</a>
                            on {{ post.date }}
                            {% if is_admin %}
                            <a href="{{ url_for('delete_post', id=post.id) }}">✘</a>
                            {% endif %}
                        </p>
                    </div>
                    <!-- Divider-->
                    <hr class="my-4" />
                    {% endfor %}
                    {% if is_admin %}
                    <div class="d-flex justify-content-end mb-4"><a class="btn btn-primary text-uppercase" href="{{ url_for('new_post') }}">Create New Post</a></div>
                    {% endif %}
                </div>
            </div>
</div>
{% endblock %}

我尝试将“expire-on-commit”设置为 False 以消除错误,但这仍然不起作用。另外,如果我尝试使用不存在的列,Jinja 会完全忽略它。使用除作者之外的任何现有列都可以完美地工作。

如果你能帮忙,那就太好了。

python-3.x database flask-sqlalchemy
1个回答
0
投票

在模板中,您正在访问

Post.author
。但是,由于
author
是一种关系,因此当您查询
Post
对象时,不会自动获取。当模板中发生访问时,SQLAlchemy 会发出一个查询来获取与
User
对应的
Post.author
实例,但会话不再活动,因此您会得到
DetachedInstanceError

为了防止这种情况,可以在关系上设置lazy='joined',以便在获取

Post.author
时始终获取
Post

author: Mapped["User"] = relationship('User', lazy='joined', back_populates="posts")

或将其指定为相关查询中的选项:

from sqlalchemy.orm import joinedload
...
posts = db.session.execute(db.select(Post).options(joinedload(Post.author)).order_by(Post.id))

上面的示例应该可以解决问题,但请注意,在 SQLAlchemy 中有很多关系加载方法 - 值得您熟悉它们,以确保您为手头的任务选择正确的方法。

© www.soinside.com 2019 - 2024. All rights reserved.