Я пытаюсь создать приложение Dash, которое интегрировано в приложение Flask. Кажется, все работает нормально, но когда я пытаюсь показать зарегистрированного пользователя в приложении Dash, оно появляется как «Нет».

Структура моего приложения следующая:

example/
example/
  dashapp/
    static/
      custom-css.css
    templates/
      base.html
      home.html
      login.html
    __init__.py
    app1.py
    forms.py
    models.py
    routes.py
  application.py
  config.py
  users.db

Мое приложение Dash находится в app1.py. Я пробовал несколько способов пройти current_user, но безуспешно. Хотя в home.html все хорошо. Думаю, проблема в том, что мое приложение находится в отдельном файле, а не в routes.py.

Вот код для app.py:

import dash
import dash_html_components as html
from dashapp import application
from flask_login import login_required, current_user


app1 = dash.Dash(__name__, server = application, routes_pathname_prefix = '/app1/', assets_folder = 'static', assets_url_path = '/static')
app1.scripts.config.serve_locally = True
app1.css.config.serve_locally = True

app1.layout = html.Div(
    children = '{}'.format(current_user)
)

for view_func in app1.server.view_functions:
    if view_func.startswith('/app1/'):
        app1.server.view_functions[view_func] = login_required(app1.server.view_functions[view_func])

routes.py код:

from flask import render_template, flash, redirect, url_for, request
from flask_login import login_user, logout_user, current_user, login_required
from werkzeug.urls import url_parse
from dashapp import application, db
from dashapp.forms import LoginForm
from dashapp.models import User
from dashapp import app1


@application.route('/')
@application.route('/home')
@login_required
def home():
    return render_template('home.html')

@application.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        next_page = request.args.get('next')
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('home')
        return redirect(next_page)
    return render_template('login.html', form=form)

@application.route('/app1/')

@application.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('login'))

Другие сценарии в значительной степени стандартные, и я не буду включать их в вопрос, если они действительно не нужны.

Подскажите пожалуйста как побороть мою проблему. Благодарность!

5
Mudyla 14 Окт 2019 в 18:23

2 ответа

Мне удалось это исправить с некоторой помощью. На случай, если кто-нибудь застрянет, смотрите обновленный код ниже.

Добавлены session строки для хранения текущего имени пользователя в routes.py:

from flask import render_template, flash, redirect, url_for, request, session
from flask_login import login_user, logout_user, current_user, login_required
from werkzeug.urls import url_parse
from dashapp import application, db
from dashapp.forms import LoginForm
from dashapp.models import User
from dashapp import app1

@application.route('/')
@application.route('/home')
@login_required
def home():
    return render_template('home.html')

@application.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        session['username'] = current_user.username
        return redirect(url_for('home'))
    form = LoginForm()
    if form.validate_on_submit():
        session['username'] = form.username.data
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        next_page = request.args.get('next')
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('home')
        return redirect(next_page)
    return render_template('login.html', form=form)

@application.route('/logout')
def logout():
    session.pop('username', None)
    logout_user()
    return redirect(url_for('login'))

И session в обратном вызове для app1.py:

import dash
import dash_html_components as html
from dash.dependencies import Input, Output
from dashapp import application
from flask_login import login_required
from flask import session

app1 = dash.Dash(__name__, server = application, routes_pathname_prefix = '/app1/', assets_folder = 'static', assets_url_path = '/static')
app1.scripts.config.serve_locally = True
app1.css.config.serve_locally = True

app1.layout = html.Div(
    children = [
        html.Div(id='div2'),
        html.Div(id='div3', children = 'xxxx'),
    ],
)

@app1.callback(
    Output('div2', 'children'),
    [Input('div3', 'children')])
def update_intervalCurrentTime(children):
    return session.get('username', None)

for view_func in app1.server.view_functions:
    if view_func.startswith('/app1/'):
        app1.server.view_functions[view_func] = login_required(app1.server.view_functions[view_func])
5
Mudyla 16 Окт 2019 в 01:29

Столкнулся с такой же проблемой. Я предполагаю, что проблема в том, что текущий пользователь не был инициализирован, когда «приложение» регистрирует приложение Dash. Хороший обходной путь, хотя кажется немного небезопасным, поскольку сеансы Flask просто кодируются.

https://github.com/RafaelMiquelino/dash-flask- login / blob / master / app.py - на мой взгляд, более надежное решение. Он проверяет current_user в обратных вызовах и использует содержимое страницы в качестве входных данных, поэтому обратные вызовы вызываются при загрузке страницы. Вы также можете пропустить защиту представлений, если взаимодействие с пользователем не является проблемой.

Вот упрощенный пример того, как я его использовал:

@app.callback(
    Output('graph-wrapper', 'children'),
    [Input('page-content', 'children')])
def load_graph(input1):
    if current_user.is_authenticated:
        return dcc.Graph() # Dash Graph populated with current_user data from db
    else:
        return ''
0
sweet_sauce 15 Фев 2020 в 11:24