3

我想要一个动态导航菜单,如果用户当前未登录,则显示“登录”,如果用户已登录,则显示“注销”。

我正在使用类似于以下的代码:

import flask
import flask_nav
import flask_nav.elements as fne

frontend = flask.Blueprint('frontend', __name__)

application = flask.Flask(__name__)
mySess = flask_session.Session()

flask_appconfig.AppConfig(application)
flask_bootstrap.Bootstrap(application)
application.register_blueprint(frontend)
application.config['BOOTSTRAP_SERVE_LOCAL'] = True
application.config['SSL'] = True
application.secret_key = SECRET_KEY
application.config['SESSION_TYPE'] = SESSION_TYPE

mySess.init_app(application)

nav = flask_nav.Nav()

class CustomRenderer(flask_bootstrap.nav.BootstrapRenderer):
    def visit_Navbar(self, node):
        nav_tag = super(CustomRenderer, self).visit_Navbar(node)
        nav_tag['class'] = 'navbar navbar-default navbar-fixed-top'
        return nav_tag

flask_nav.register_renderer(application, 'custom', CustomRenderer)

nav.init_app(application)

@nav.navigation()
def top_nav():
    items = [ fne.View('Home',              '.index') ]

    if 'google_token' in flask.session:
        items.append(fne.View('Logout',         '.logout'))
    elif 'auth_url' in flask.session:
        items.append(fne.View('Login',          flask.session['auth_url']))
    else:
        items.append(fne.View('Login',          '.login'))

    items.append(fne.View('About',              '.about'))
    items.append(fne.View('Contact',            '.contact'))
    items.append(fne.View('Shop',               '.shop'))
    items.append(fne.View('Help & Feedback',    '.help'))

    return fne.Navbar('', *items)

nav.register_element('frontend_top', top_nav())

不幸的是,Flask 会话变量超出了 nav 对象的范围,因此我无法从 top_nav 中访问 flask.session。

例如,当我在我的应用程序之外创建用于访问烧瓶会话的任何独立功能时,我遇到了同样的困难

def user_is_logged_in():
    if 'google_token' in flask.session:
        return True
    else:
        return False
    return False

这些函数给出了预期的错误“RuntimeError:在请求上下文之外工作”。

出于安全原因,我不想在我的 application.py 代码中为用户使用全局变量,因此多人可以同时访问应用程序而不会出错。我相信 SESSION 应该存储用户当前是否登录。

如何让我的 flask_nav.Nav() 查看我的应用程序的 flask.session?

4

2 回答 2

3

flask_nav在开始处理请求之前,在应用程序生命周期的某个阶段注册扩展。

当应用程序中存在请求上下文时,您可以稍后覆盖 template_global 的注册。

排除常见的导航项。

nav = Nav()

# registers the "top" menubar
navitems = [
    View('Widgits, Inc.', 'index'),
    View('Our Mission', 'about'),
]

设置函数以根据会话中的值返回适当的视图/链接

def with_user_session_action(items):
    return (
        items 
        + [ View('Login', 'login') if not session.get('logged') else View('Logout', 'logout')]
    )

在委托给 nav.register_element 的函数中使用它

def register_element(nav, navitems):
    navitems = with_user_session_action(navitems)
    return nav.register_element('top', 
        Navbar(*navitems)
    )

取代 render_template 以始终传递计算的导航

_render_template = render_template

def render_template(*args, **kwargs):
    register_element(nav, navitems)

    return _render_template(*args, nav=nav.elems, **kwargs)

奖金:

您可以缓存计算的登录/注销导航,这样它就不会只为每种情况计算一次。

于 2017-10-10T11:37:19.923 回答
1

Flask-Login将使您的生活更轻松。它提供了一个current_user指向当前用户的指向,并且用户对象有一个is_authenticated属性:

from flask_login import current_user
...
@nav.navigation()
def top_nav():
    ...
    if current_user.is_authenticated: 
        items.append(View("Logout", ".logout")) 
    else: 
        items.append(View("Login", ".login"))

初始化 Flask-Login 的代码如下:

from flask import Flask
from flask_login import LoginManager, UserMixin

app = Flask(__name__)
login_manager = LoginManager(app)

# The user model
class User(db.Model, UserMixin):
    ...


@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)

查看文档以获取更多详细信息。

于 2017-10-04T00:47:44.003 回答