我正在使用flask-sqlalchemy和flask-login。
我的烧瓶登录用户加载器目前看起来像这样:
@login_manager.user_loader
def load_user(user_id):
return User.query.filter_by(id=user_id).options(load_only('id')).first()
这意味着每次用户需要登录load_user()
将运行数据库查询以返回User对象。在我的情况下,我几乎从不需要其他用户字段,如电子邮件,名称等,所以我指定sqlalchemy只加载id字段。这将允许mysql优化器相当快地执行查询。
但是,我甚至不需要执行此查询,因为:
此外,由于某些特定的商业原因,每个登录用户必须每1秒发送一次心跳信号。这意味着每秒都会执行此用户ID提取查询,从而在我的数据库服务器上产生相当大的负载(我有大约1000个用户同时执行此操作)。这个要求是不可协商的,我无法通过其他方法提高速度,例如使用内存服务器。
我想这样做:
@login_manager.user_loader
def load_user(user_id):
return User(id=user_id)
请注意,在这种情况下,将返回具有用户ID的伪对象。
从其他文件,我做
from flask_login import current_user
以上一行为我提供了当前登录用户的句柄。
然而,当我想要获取用户的其他属性时,使用我提出的方法将无法工作,更重要的是它的关系。
这意味着我不能简单地执行current_user.email
或:
current_user.friends #this is a relationship
我尝试了这个,它只返回None
。 (但是,我可以像通常那样获得用户的身份)
有没有办法实例化一个模型并让sqlalchemy认为我在创建模型时指定的任何属性都是sqlalchemy查询的结果?
从本质上讲,sqlalchemy认为只使用load_only()
方法加载了一些属性。
这样,如果我current_user.email
,它会在未加载的情况下获取电子邮件。
答案 0 :(得分:1)
在与Michael Bayer(sqlalchemy的创建者)here讨论此问题之后,这是他建议的解决方案:
使对象像分离和过期一样,然后与会话关联:
from sqlalchemy.orm.session import make_transient_to_detached
@login_manager.user_loader
def load_user(user_id):
u = User(id=int(user_id)) # will not do any db query
make_transient_to_detached(u) # This is the suggested solution
db.session.add(u) # add the detached object to session
return u
稍后,可以这样做:
from flask_login import current_user
并访问current_user的其他属性,如:
print(current_user.email) # will perform a database query to fetch email