在我的webapp中,每个页面都要用到同一个一般不会变化的查询结果,为避免每次访问都需查询一次这个变量,我在views.py中弄了一个全局变量ADMIN_NOTES
ADMIN_NOTES=Note.query.filter_by(author_id=ADMIN.id).all()
而当ADMIN_NOTE会发生变化时,如此时管理员又写入了一个新note,则重新查询数据库获得最新的ADMIN_NOTE的值,尽量减少访问数据库的次数
我本想这么实现的(中间部分不重要的代码省略了)
#全局变量
ADMIN_NOTES=Note.query.filter_by(author_id=ADMIN.id).all()
#写入新note的函数1
@app.route('/new_note',methods=['GET','POST'])
def new_note():
global ADMIN_NOTES
data=json.loads(request.get_data())
note=Note(title=data['note_title'],upload_time=datetime.utcnow())
db.session.add(note)
db.session.commit()
#若是管理员写入新note,则重新查询并修改全局变量ADMIN_NOTES
if note.author.nickname=='ADMIN':
ADMIN_NOTES=Note.query.filter_by(author_id=ADMIN.id).all()
KAFENUT_NOTES[0].author.nickname #能正确访问ADMIN_NOTES
print(len(ADMIN_NOTES)) #正确访问ADMIN_NOTES
resp['success']=True
resp['text']='Upload successfully!'
resp['url']=url_for('note',note_id=note.id,nickname=note.author.nickname) #浏览器接受到服务器的json之后跳转到,resp[url]所指示的页面,即下面这个页面
return json.dumps(resp)
#返回note页面的函数2
@app.route('/<nickname>/note/<note_id>',methods=['GET','POST'])
def note(nickname,note_id):
global ADMIN_NOTES
user=User.query.filter_by(nickname=nickname).first()
note=Note.query.filter_by(id=note_id).first()
if request.method=='GET':
note.view_num+=1
db.session.add(note)
db.session.commit()
for nnote in ADMIN_NOTES:
print(nnote.author.nickname) #出错位置
return render_template('note_page.html',note=note,admin_notes=ADMIN_NOTES)
然而问题也正出在这里,当管理员写入新的note之后(即ADMIN_NOTES这个全局变量发生变化之后)重新查询的语句虽然在函数1中执行了(print出的note数量是写入新note之后的数量,)。但当用户根据函数1返回的json跳转到函数2的时候,函数2内就无法正确访问ADMIN_NOTES,准确来说无法访问nnote.author.nickname,其中author是note表用author_id这个外键连接到user表得到的,错误栈如下
Traceback (most recent call last):
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\_compat.py", line 33, in reraise
raise value
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\_compat.py", line 33, in reraise
raise value
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\flask\app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "E:\vs\python\AwesomeWebApp\AwesomeWebApp\app\views.py", line 232, in note
print(nnote.author.nickname) #let author.id be preloaded
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\sqlalchemy\orm\attributes.py", line 282, in __get__
return self.impl.get(instance_state(instance), dict_)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\sqlalchemy\orm\attributes.py", line 710, in get
value = self.callable_(state, passive)
File "C:\Users\MSI-1\Anaconda3\lib\site-packages\sqlalchemy\orm\strategies.py", line 688, in _load_for_state
% (orm_util.state_str(state), self.key)
sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <Note at 0x26de5f41198> is not bound to a Session; lazy load operation of attribute 'author' cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)
sqlalchemy报出detached错误
sqlalchemy.orm.exc.DetachedInstanceError: Parent instance is not bound to a Session; lazy load operation of attribute 'author' cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)
这该怎么解决?或者还有什么其他方法实现:在我的webapp中,每个页面都要用到同一个一般不会变化的查询结果,为避免每次访问都需查询一次这个一般不会变量,我在views.py中弄了一个全局变量ADMIN_NOTES。而当ADMIN_NOTE会发生变化时,如此时管理员又写入了一个新note,则重新查询数据库获得最新的ADMIN_NOTE的值,尽量减少访问数据库的次数