saz*_*azr 14 python session sqlalchemy python-2.7 flask-sqlalchemy
我正在尝试为应用程序运行服务器,但我在登录时遇到错误:
[!] Object '<User at 0x7f12bc185a90>' is already attached to session '2' (this is '3')
Run Code Online (Sandbox Code Playgroud)
我正在添加的会话似乎已经存在于数据库中.这是导致问题的代码片段:
@app.route('/login', methods=['POST'])
def login():
u = User.query.filter(User.username == request.form["username"]).first()
if not u or u.password != request.form["password"]:
return error("E1")
s = Session.get_by_user(u)
if s is not None:
db_session.delete(s)
db_session.commit()
print db_session.execute("SELECT * FROM sessions").fetchall()
s = Session(u)
db_session.add(s)
db_session.commit()
return jsonify(s.values)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我在尝试添加任何内容之前从会话表中打印内容,它是空的!([])
还有什么可能导致这个?
这是"会话"实施:
class Session(Base):
__tablename__ = "sessions"
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'), unique=True)
user = relationship(User)
key = Column(String(50), unique=True)
created = Column(DateTime)
def __init__(self, user=None):
self.user = user
self.key = base64.encodestring(os.urandom(24)).strip()
self.created = datetime.now()
def __repr__(self):
return '<Session %r>' % (self.key)
@property
def values(self):
return {"username" : self.user.username,
"key" : self.key,
"created" : str(self.created),
}
@classmethod
def get_by_key(cls, key):
s = cls.query.filter(cls.key == key).first()
#print datetime.now() - s.created
if s and datetime.now() - s.created > settings.SESSION_LIFETIME:
s = None
return s
@classmethod
def get_by_user(cls, user):
s = cls.query.filter(cls.user == user).first()
if s and datetime.now() - s.created > settings.SESSION_LIFETIME:
s.query.delete()
db_session.commit()
s = None
return s
Run Code Online (Sandbox Code Playgroud)
mar*_*ski 12
您尝试修改的对象已附加到另一个会话.也许您输入错误,db_session是一个新实例.
一个很好的解决方法是提取当前绑定的会话并使用它:
代替:
db_session.add(s)
Run Code Online (Sandbox Code Playgroud)
做:
current_db_sessions = db_session.object_session(s)
current_db_sessions.add(s)
Run Code Online (Sandbox Code Playgroud)
正如@marcinkuzminski所提到的,您无法添加已附加到另一个会话的对象.object_session()但是,如果您不确定会话是否源自您当前正在操作的相同线程上下文,那么从对象中拉入原始会话是有风险的.线程安全的方法是使用merge():
local_object = db_session.merge(original_object)
db_session.add(local_object)
db_session.commit()
Run Code Online (Sandbox Code Playgroud)
小智 7
此错误意味着您正在处理的记录附加到 2 个不同的会话 ( db)!
原因之一是您可以使用一个定义模型并使用db = SQLAlchemy(app)另一个添加/插入/修改数据库!
我的解决方案是统一数据库!
尝试这个:
u = db.session.query(User).filter(User.username == request.form["username"]).first()
Run Code Online (Sandbox Code Playgroud)
而不是这个:
u = User.query.filter(User.username == request.form["username"]).first()
Run Code Online (Sandbox Code Playgroud)
如果您要相互导入server.py和model.py,则会出现此数据库会话问题
server.py
from flask import Flask
import os
import models as appmod #################### importing models here in server.py<----------
app = Flask(__name__) # L1
app.config.from_object(os.environ['APP_SETTINGS']) # L2
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # L3
database = SQLAlchemy(app) # L4
db = database # L5
@app.route('/item_delete/<id>', methods=['DELETE'])
def remove_method(id = None):
data_rec = appmod.Employee.query.get(id)
db.session.delete(data_rec)
db.session.commit()
return "DELETE"
if __name__ == '__main__':
app.run(port=5000, host='0.0.0.0',debug=True,threaded=True)
Run Code Online (Sandbox Code Playgroud)
models.py
from server import db #################### importing server in models.py here <------------
from sqlalchemy.dialects.mysql import JSON
class Employee(db.Model):
__tablename__ = 'employe_flask'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
datetime = db.Column(db.DateTime)
designation = db.Column(db.String(128))
def __init__(self, name, datetime, designation):
self.name = name
self.datetime = datetime
self.designation = designation
@staticmethod
def delete_rec(data_rec):
db.session.delete(data_rec)#.delete
db.session.commit()
def __repr__(self):
record = {"name":self.name,"date":self.datetime.ctime(),"designation":self.designation}.__str__()
return record
Run Code Online (Sandbox Code Playgroud)
从server.py中删除L1到L5行,并将其放置在settings.py之类的通用文件中,并将'app'和'db'导入server.py并在models.py中导入db
喜欢下面的文件
server.py
from flask import Flask
import os
import models as appmod
from settings import app, db
@app.route('/item_delete/<id>', methods=['DELETE'])
def remove_method(id = None):
data_rec = appmod.Employee.query.get(id)
db.session.delete(data_rec)
db.session.commit()
return "DELETE"
if __name__ == '__main__':
app.run(port=5000, host='0.0.0.0',debug=True,threaded=True)
Run Code Online (Sandbox Code Playgroud)
settings.py
import os
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__) # L1
app.config.from_object(os.environ['APP_SETTINGS']) # L2
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # L3
database = SQLAlchemy(app) # L4
db = database # L5
Run Code Online (Sandbox Code Playgroud)
models.py
from settings import db
from sqlalchemy.dialects.mysql import JSON
class Employee(db.Model):
__tablename__ = 'employe_flask'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
datetime = db.Column(db.DateTime)
designation = db.Column(db.String(128))
def __init__(self, name, datetime, designation):
self.name = name
self.datetime = datetime
self.designation = designation
@staticmethod
def delete_rec(data_rec):
db.session.delete(data_rec)#.delete
db.session.commit()
def __repr__(self):
record = {"name":self.name,"date":self.datetime.ctime(),"designation":self.designation}.__str__()
return record
Run Code Online (Sandbox Code Playgroud)