博客
关于我
(数据科学学习手札119)Python+Dash快速web应用开发——多页面应用
阅读量:424 次
发布时间:2019-03-06

本文共 6037 字,大约阅读时间需要 20 分钟。

Python + Dash 快速开发多页面Web应用

项目简介

本文是“Python + Dash 快速开发多页面Web应用”教程系列的第16篇。在前面的教程中,我们通过搭建单页面的Dash应用,掌握了如何快速开发功能丰富的Web应用。然而随着应用的功能日趋完善,单页面的内容组织方式逐渐无法满足复杂的需求,也不利于构建逻辑清晰的Web应用。

因此,我们需要在Dash应用中引入路由功能。通过在主域名下根据不同的URL渲染不同内容,就像大多数现代网站一样实现多页面应用。

本文将教你如何在Dash中编写多页面应用并进行路由控制。

Dash 应用路由基础

2.1 Location 组件的基础使用

要在Dash中实现URL路由,首先需要捕获浏览器地址栏中的URL信息。Dash中可以通过构建可以持续监听当前应用URL信息的组件来实现。

我们使用dash_core_components中的Location()组件。其核心属性包括hrefpathnamesearchhash,可以记录地址栏中的相应信息。

以下示例展示了如何通过Location()组件捕获不同URL参数:

app1.pyimport dashimport dash_core_components as dccimport dash_html_components as htmlfrom dash.dependencies import Input, Outputapp = dash.Dash(__name__)app.layout = dcc.Container([    dcc.Location(id='url'),    html.Ul(id='output-url')], style={'paddingTop': '100px'})@app.callback(    Output('output-url', 'children'),    [Input('url', 'href'),     Input('url', 'pathname'),     Input('url', 'search'),     Input('url', 'hash')])def show_location(href, pathname, search, hash):    return [        html.Li(f'当前href为:{href}'),        html.Li(f'当前pathname为:{pathname}'),        html.Li(f'当前search为:{search}'),        html.Li(f'当前hash为:{hash}')    ]if __name__ == '__main__':    app.run_server(debug=True)

2.2 利用 Location 实现页面重定向

除了捕获URL信息,Location()组件还可以用于实现页面重定向。通过将Location()作为回调函数的输出(记得设置id属性),地址栏URL会在回调完成后跳转。

以下示例展示了如何通过Location()实现重定向:

app3.pyimport dashimport dash_core_components as dccimport dash_html_components as htmlfrom dash.dependencies import Input, Outputapp = dash.Dash(__name__)app.layout = html.Div([    html.Div(id='redirect-url-container'),    dbc.Button('跳转到页面A', id='jump-to-pageA', style={'marginRight': '10px'}),    dbc.Button('跳转到页面B', id='jump-to-pageB'),], style={'paddingTop': '100px'})@app.callback(    Output('redirect-url-container', 'children'),    [Input('jump-to-pageA', 'n_clicks'),     Input('jump-to-pageB', 'n_clicks')])def jump_to_target(a_n_clicks, b_n_clicks):    ctx = dash.callback_context    if ctx.triggered[0]['prop_id'] == 'jump-to-pageA.n_clicks':        return dcc.Location(id='redirect-url', href='/pageA')    elif ctx.triggered[0]['prop_id'] == 'jump-to-pageB.n_clicks':        return dcc.Location(id='redirect-url', href='/pageB')    return dash.no_updateif __name__ == '__main__':    app.run_server(debug=True)

除了Location()组件,dash_core_components中的Link()组件提供了更好的替代方案。Link()组件的refresh参数默认为False,实现了无缝页面切换。

以下示例展示了如何使用Link()组件实现无缝切换:

app4.pyimport dashimport dash_core_components as dccimport dash_html_components as htmlfrom dash.dependencies import Input, Outputapp = dash.Dash(__name__)app.layout = dbc.Container([    dcc.Location(id='url'),    dcc.Link('页面A', href='/pageA', refresh=True),    html.Br(),    dcc.Link('页面B', href='/pageB'),    html.Hr(),    html.H1(id='render-page-content')], style={'paddingTop': '100px'})@app.callback(    Output('render-page-content', 'children'),    Input('url', 'pathname'))def render_page_content(pathname):    if pathname == '/':        return '欢迎来到首页'    elif pathname == '/pageA':        return '欢迎来到页面A'    elif pathname == '/pageB':        return '欢迎来到页面B'    elif pathname == '/pageC':        return '欢迎来到页面C'    else:        return '当前页面不存在!'if __name__ == '__main__':    app.run_server(debug=True)

动手开发个人博客网站

掌握以上知识后,我们来用Dash开发一个简单的个人博客网站。思路是在Location监听URL变化的前提下,后台利用网络爬虫从博客园Dash主题下爬取相应网页内容,并根据用户访问渲染对应文章。

以下是一个实现示例:

app5.pyimport dashimport dash_core_components as dccimport dash_html_components as htmlimport dash_bootstrap_components as dbcimport dash_dangerously_set_inner_htmlfrom dash.dependencies import Input, Outputimport reimport requestsfrom lxml import etreeapp = dash.Dash(__name__, suppress_callback_exceptions=True)app.layout = html.Div(    dbc.Spinner(        dbc.Container([            dcc.Location(id='url'),            html.Div(id='page-content')        ], style={            'paddingTop': '30px',            'paddingBottom': '50px',            'borderRadius': '10px',            'boxShadow': 'rgb(0 0 0 / 20%) 0px 13px 30px, rgb(255 255 255 / 80%) 0px -13px 30px'        }),        fullscreen=True    )))@app.callback(    Output('article-links', 'children'),    Input('url', 'pathname'))def render_article_links(pathname):    response = requests.get('https://www.cnblogs.com/feffery/tag/Dash/',                           headers={                               'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'                           })    tree = etree.HTML(response.text)    posts = [        (href, title.strip())        for href, title in zip(            tree.xpath("//div[@class='postTitl2']/a/@href"),            tree.xpath("//div[@class='postTitl2']/a/span/text()")        )    ]    return [        html.Li(            dcc.Link(title, href=f'/article-{href.split("/")[-1]}', target='_blank')        ) for href, title in posts    ]@app.callback(    Output('page-content', 'children'),    Input('url', 'pathname'))def render_article_content(pathname):    if pathname == '/':        return [            html.H2('博客列表:'),            html.Div(                id='article-links',                style={'width': '100%'}            )        ]    elif pathname.startswith('/article-'):        response = requests.get(            f'https://www.cnblogs.com/feffery/p/{re.findall("\d+", pathname)[0]}.html',            headers={                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'            }        )        tree = etree.HTML(response.text)        return [            html.H3(tree.xpath("//title/text()")[0].split(' - ')[0]),            html.Em('作者:费弗里'),            dash_dangerously_set_inner_html.DangerouslySetInnerHTML(                unescape(etree.tostring(                    tree.xpath('//div[@id="cnblogs_post_body"]')[0],                    method='text'                ).decode())            )        ]    return dash.no_updateif __name__ == '__main__':    app.run_server(debug=True)

按照类似的方法,你可以根据需求开发自己的多页面应用,并进一步丰富功能。

你可能感兴趣的文章
php多线程
查看>>
PHP大数组循环-避免产生Notice或者是Warning
查看>>
PHP大数组过滤元素、修改元素性能分析
查看>>
PHP大文件切片下载代码
查看>>
PHP如何下载远程文件到指定目录
查看>>
php如何优化压缩的图片
查看>>
php如何做表格,新手怎么制作表格
查看>>
RabbitMQ高级特性
查看>>
php如何定义的数位置,php如何实现不借助IDE快速定位行数或者方法定义的文件和位置...
查看>>
RabbitMQ集群 - 普通集群搭建、宕机情况
查看>>
php如何正确的获得文件的后缀名
查看>>
PHP如何生成唯一的数字ID
查看>>
PHP如何获取当前页面的最后修改时间
查看>>
PHP如何读取json数据
查看>>
PHP字符串
查看>>
PHP字符串递增
查看>>
php学习之基础语法
查看>>
RabbitMQ集群 - 仲裁队列、Raft协议(最详细的选举流程)
查看>>
PHP学习总结(11)——PHP入门篇之WAMPServer多站点配置
查看>>
PHP学习总结(12)——PHP入门篇之变量
查看>>