我已经构建了一个自定义会话处理程序,它将重要位存储在数据库中,只是将ID保存在默认的Flask会话中(这是一个加密的cookie)。每次加载页面时,会读取会话数据(或使用新ID创建),然后在退出时会话将保存到数据库中。我基本上遵循PHP会话的想法,但将其保存在数据库中而不是文件中。
我已使用__enter__
和__exit__
进行设置,以便像这样工作:
@app.route('/')
def main():
with SessionHandler(mysql) as session:
#Get a new session ID but keep the session data
session.regenerate()
#Add 1 to session variable
try:
session['count'] += 1
except KeyError:
session['count'] = 1
#Other code here
我正在考虑手动执行登录(例如,如果用户未登录,则重定向到页面),但我遇到了@login_required
,这似乎是一种不错的做事方式。
这是其中一个默认实现:
def login_required(function_to_protect):
@wraps(function_to_protect)
def wrapper(*args, **kwargs):
user_id = session.get('user_id')
if user_id:
user = database.get(user_id)
if user:
# Success!
return function_to_protect(*args, **kwargs)
else:
flash("Session exists, but user does not exist (anymore)")
return redirect(url_for('login'))
else:
flash("Please log in")
return redirect(url_for('login'))
@app.route('/')
@login_required
def main():
return 'you are logged in'
但是,如果我要将其与我自己的会话变量相关联,那么我必须在每个页面的会话上进行另一次数据库查找。
有没有办法可以将这两种方法结合起来,这样我就可以在装饰器中访问会话数据而无需再次从数据库中读取数据?如果我可以简化with SessionManager(mysql) as session
部分,它也是一个奖励,因为每个功能现在都有2个级别的缩进,我不太确定是否有方法绕过
如果它有用,可以在这里上课(仍为在制品):
class SessionManager(object):
def __init__(self, db_connection):
self.sql = db_connection.sql
def __enter__(self):
try:
session_id = session['sid']
hash = quick_hash(session_id)
session_data = self.sql('SELECT data_pickle, last_activity FROM temporary_storage WHERE id = %s', hash)
if session_data and session_data[0][1] > time.time() - SESSION_TIMEOUT:
self.hash = hash
self.data = cPickle.loads(session_data[0][0])
self._new_id = False
return self
else:
raise KeyError
except KeyError:
self.new()
return self
def __getitem__(self, item):
return self.data[item]
def __setitem__(self, item, value):
self.data[item] = value
def get(self, item, default):
return self.data.get(item, default)
def new(self):
self.regenerate()
self.data = {}
def regenerate(self):
while True:
session_id = uuid.uuid4().hex
hash = quick_hash(session_id)
if not self.sql('SELECT count(*) FROM temporary_storage WHERE id = %s', hash):
session['sid'] = session_id
self.hash = hash
self._new_id = True
return session_id
def __exit__(self, *args):
data = cPickle.dumps(self.data)
if self._new_id:
self.sql('INSERT INTO temporary_storage (id, data_pickle, last_activity) VALUES(%s, %s, UNIX_TIMESTAMP(NOW()))', self.hash, data)
else:
self.sql('UPDATE temporary_storage SET data_pickle = %s, last_activity = UNIX_TIMESTAMP(NOW()) WHERE id = %s', data, self.hash)
答案 0 :(得分:1)
你可以创建一个带有这样一个参数的装饰器:
awk '{print FILENAME, $0}' "${PFILE}"
最外层函数将装饰器创建为一个知道def with_session_handler(driver):
def decorator(func_to_wrap):
@wraps(func_to_wrap)
def wrapper(*args, **kwargs):
with SessionHandler(driver) as session:
return func_to_wrap(*args, **kwargs, session=session)
return wrapper
return decorator
对象的闭包。它一直显示在driver
函数中,您可以在调用包装函数时在wrapper
语句中使用它。
然后使用它:
with