Flask sqlalchemy:移动模型会导致InvalidRequestError-已附加到会话

Flask sqlalchemy:移动模型会导致InvalidRequestError-已附加到会话,flask,sqlalchemy,flask-sqlalchemy,Flask,Sqlalchemy,Flask Sqlalchemy,将我的模型移动到它们自己的模块会导致InvalidRequestError。。这似乎与数据库会话和我在模型模块中导入db的方式有关 我试图将这个问题减少到所需的最少代码量。首先,一个工作烧瓶应用程序: import os from flask import Flask, render_template, request from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SECRET_KEY']

将我的模型移动到它们自己的模块会导致InvalidRequestError。。这似乎与数据库会话和我在模型模块中导入db的方式有关

我试图将这个问题减少到所需的最少代码量。首先,一个工作烧瓶应用程序:

import os

from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SECRET_KEY'] = 'somesecret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.instance_path, 'app.db')
db = SQLAlchemy(app)


class Thing(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String(300), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

    def __init__(self, user, text):
        self.user = user
        self.text = text


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    things = db.relationship('Thing', backref='user', lazy='dynamic')

    def __init__(self, username):
        self.username = username


@app.route('/', methods=['GET', 'POST'])
def add():
    if request.method == 'POST':
        username = request.form['username']
        text = request.form['txt']

        user = User.query.filter_by(username=username).first()
        thing = Thing(user, text)

        db.session.add(thing)
        db.session.commit()

    return render_template('index.html')

def initdb():
    db.create_all()
    db.session.add(User('test'))
    db.session.commit()

if __name__ == '__main__':
    app.run(debug=True)
索引模板也是最小的:

<html>
  <head>
  </head>
  <body>
        <form method="post">
          <input type="text" name="username"></input>
          <input type="text" name="txt"></input>
          <button type="submit">Submit</button>
        <form>
  </body>
</html>
新的app.py看起来像:

import os

from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SECRET_KEY'] = 'somesecret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.instance_path, 'app.db')
db = SQLAlchemy(app)

#This line changes
import models


@app.route('/', methods=['GET', 'POST'])
def add():
    if request.method == 'POST':
        username = request.form['username']
        text = request.form['txt']

        # these 2 lines change: using models now
        user = models.User.query.filter_by(username=username).first()
        thing = models.Thing(user, text)

        db.session.add(thing)
        db.session.commit()

    return render_template('index.html')

def initdb():
    db.create_all()
    db.session.add(User('test'))
    db.session.commit()

if __name__ == '__main__':
    app.run(debug=True)
现在发布表单时会出现以下错误:

sqlalchemy.exc.InvalidRequestError
InvalidRequestError: Object '<Thing at 0x11111b950>' is already attached to session '1' (this is '2')
当我调试它时,有趣的是,用户连接到的会话与我尝试添加到的会话不同。显然,db导入会导致模型类的数据库会话出错?有人能向我解释一下这里发生了什么事吗


顺便说一下,我可以通过更改Thing类的init并分配user_id而不是user来解决这个问题。这样,Thing实例就不会从用户实例复制会话。但这并不能解释为什么用户实例一开始就有一个不正确的会话。

您已经两次无意中导入了app.py模块。下面是发生的情况:

您可以键入$python path/to/app.py 解释器创建一个名为_umain _;的模块,并在其中执行app.py。 您导入模型,然后模型又导入应用程序。 没有名为app的模块,解释器将创建名为app的模块,并再次在其中执行app.py 您的models.py正在使用app.db,但实际运行的flask实例实际使用的是_main__;u.db。 修复此问题的最佳方法是添加第三个模块,以便将其称为main,比如main_app.py,只包含:

import app
if __name__ == '__main__':
    app.app.run(debug=True)

并去掉app.py中相应的if main子句。然后使用$python path/to/main_app.py运行应用程序。

您已经两次无意中导入了app.py模块。下面是发生的情况:

您可以键入$python path/to/app.py 解释器创建一个名为_umain _;的模块,并在其中执行app.py。 您导入模型,然后模型又导入应用程序。 没有名为app的模块,解释器将创建名为app的模块,并再次在其中执行app.py 您的models.py正在使用app.db,但实际运行的flask实例实际使用的是_main__;u.db。 修复此问题的最佳方法是添加第三个模块,以便将其称为main,比如main_app.py,只包含:

import app
if __name__ == '__main__':
    app.app.run(debug=True)

并去掉app.py中相应的if main子句。然后用$python path/to/main_app.py运行应用程序。

这解决了我的问题,谢谢。我决定将整个应用程序分解为多个文件,因为这样解决了我的问题,谢谢。我决定将整个应用程序分解为多个文件,如