rje*_*rje 2 sqlalchemy flask flask-sqlalchemy
将我的模型移动到它们自己的模块会导致 InvalidRequestError .. 这似乎与数据库会话和我在模型模块中导入 db 的方式有关。
我试图将这个问题减少到必要的最少代码量。首先,一个可用的 Flask 应用程序:
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)
Run Code Online (Sandbox Code Playgroud)
索引模板,同样是最小的:
<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>
Run Code Online (Sandbox Code Playgroud)
我们可以用app.initdb()创建一个数据库,然后启动应用程序并在表单中输入一些数据(用户名应该是'test')。一个新项目被插入到 Thing 表中。好的 :)
但随后我将模型移动到 models.py 中:
from app import db
class Thing(db.Model):
...
class User(db.Model):
...
Run Code Online (Sandbox Code Playgroud)
新的 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)
Run Code Online (Sandbox Code Playgroud)
现在发布表单给了我这个错误:
sqlalchemy.exc.InvalidRequestError
InvalidRequestError: Object '<Thing at 0x11111b950>' is already attached to session '1' (this is '2')
Run Code Online (Sandbox Code Playgroud)
当我调试这个时,有趣的是用户附加到与我尝试添加的会话不同的会话。那么显然 db 导入会导致模型类的数据库会话出现问题?谁能向我解释这里发生了什么?
顺便说一下,我可以通过更改Thing 类的init并分配 user_id 而不是 user来解决这个问题。这样 Thing 实例不会从 User 实例复制会话。但这并不能解释为什么 User 实例开始时有一个不正确的会话。
您无意中导入了您的app.py模块两次。这是发生的事情:
$ python path/to/app.py__main__,并app.py在其中执行。models,然后进口app。app的模块,解释器创建一个命名的模块app并app.py在其中第二次执行models.py正在使用app.db,但实际运行的烧瓶实例实际上正在使用__main__.db.修复它的最佳方法是添加第三个模块,以便它可以称为 main,例如main_app.py,仅包含:
import app
if __name__ == '__main__':
app.app.run(debug=True)
Run Code Online (Sandbox Code Playgroud)
并去掉 app.py 中相应的 if main 子句。然后运行您的应用程序$ python path/to/main_app.py。
| 归档时间: |
|
| 查看次数: |
1366 次 |
| 最近记录: |