Перенаправление в приложении Plotly Dash

Я пытался разработать приложение с многостраничным шаблоном от Plolty Dash. Я пытаюсь реализовать перенаправление при успешном входе в систему. Структура проекта следующая:

multipage
├── app.py
├── apps
│   ├── app1.py
│   ├── app2.py
│   ├── app3.py
├── index.py
└── static
    └── base.css

Код, который у меня есть, выглядит следующим образом:

index.py (начальная точка)

from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html

from app import app, server
from apps import app1, app2, app3


app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])

@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/':
        return app3.layout
    else:
        return '404'

if __name__ == '__main__':
    server.run(debug=True)

Здесь, когда пользователь посещает /, будет отображаться страница входа (app3.py).

app.py

import dash
import os

import flask


app = dash.Dash()
server = app.server
app.config.supress_callback_exceptions = True

external_css = [
    'https://codepen.io/chriddyp/pen/bWLwgP.css',
    '/static/base.css'
]
for css in external_css:
    app.css.append_css({"external_url": css})


@app.server.route('/static/<path:path>')
def static_file(path):
    static_folder = os.path.join(os.getcwd(), 'static')
    return flask.send_from_directory(static_folder, path)

app2.py (код входа)

import flask
from dash.dependencies import Input, Output, State, Event
import dash_html_components as html
import dash_core_components as dcc
from apps import app1

from app import app

layout = html.Div(children=[
    # content
    html.Div(id='login',children=[
        html.H3("Please log in", hidden=False, id="page_header"),
        # login form
        html.Form(children=[
            html.P(children=["Username: ", dcc.Input(type='text', id='username', placeholder='username')]),
            html.P(children=["Password: ", dcc.Input(type='password', id='password', placeholder='password')]),
            html.Button(children=['Login'], type='submit', id='login_button')
        ], style={'width': '30%', 'margin': '0 auto'}, id="login_form", hidden=False)
    ], style={'display': 'block', 'text-align': 'center', 'padding': 2}),
    html.Br(),
    html.Hr(style={'width': '30%'}),
])


@app.callback(Output('login', 'children'),
              events=[Event('login_button', 'click')],
              state=[State('username', 'value'), State('password', 'value')])
def login(username, password):
    if username:
        print("login")
        return flask.redirect('/home')
    else:
        print("No Luck")

В функции login(username, password), если пользователь действителен, приложение должно перенаправить на /home, и там должен отображаться app1.py.

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


person Nikhil Baby    schedule 02.02.2018    source источник


Ответы (2)


Это похоже на то, что не должно работать, но это работает:

Сначала добавьте скрытый div для вывода вашего обратного вызова:

html.Div(id="hidden_div_for_redirect_callback")

Затем определите свой обратный вызов следующим образом (примечание: я использую flask_login):

# Note that I am currently at /login

@app.callback(Output("hidden_div_for_redirect_callback", "children"),
              [Input("login_button", "n_clicks")],
              [State('username_login', 'value'),
               State('pwsd_login', 'value'),])
def login_user_(n_clicks, uname, pswd):
    # User clicked the login button

    # Do login logic....

    if successful_login:
        return dcc.Location(pathname="/home", id="someid_doesnt_matter")

    else:
        # e.g. password doesn't match
        raise PreventUpdate()

Возвращенный dcc.Location, к сожалению, заставит страницу перезагрузиться (с любыми связанными побочными эффектами), но вы окажетесь на нужном пути. Если авторизация не удалась, вы просто предотвратите обновление.

person Kostas Mouratidis    schedule 12.07.2019

Я сделал запрос на перенос с возможностью вернуть ответ Flask, но у меня нет времени доработать его. Если вам нужно реализовать это до того, как я покрою этот PR тестами, вы можете расширить базовое приложение этими изменениями и использовать его следующим образом:

@app.callback(...)
def login():
    if username:    
        redirect_home = redirect('/home')
        response = app.make_response(redirect_home)
        return response
    else:
        return 'No luck'

Другой способ взлома - вернуть фрагмент javascript внутри тега, который изменяет свойство window.location.

person Oleh Rybalchenko    schedule 13.02.2018
comment
Ваш PR был закрыт (к сожалению), но здесь они объединили другой подход: github.com/plotly/dash / pull / 623 - person Chris; 17.05.2019