10-minute quick introduction to Python full-stack application development

The sample code for this article has been uploaded to my Github warehouse https://github.com/CNFeffery/dash-master

1 Environment Construction

The dash application is a Python project. It is recommended that you develop a good habit from the beginning and use a virtual environment to build the environment required for our dash application to run. Take my most commonly used conda as an example. The terminal executes the following command to create a file named dash- app-dev, a virtual environment with Python version 3.8:

conda create -n dash-app-dev python=3.8 -y

Activate the environment:

conda activate dash-app-dev

In this environment, use pip to install the necessary dependencies (dash+fac development kit, and autopep8 for automatically beautifying the code format during the development phase). Here, for domestic download acceleration, the Alibaba Cloud image is used:

pip install dash feffery-antd-components autopep8 -i https://mirrors.aliyun.com/pypi/simple/

So far we have completed the construction of the Python virtual environment required by the standard dash application.

2 Initialize the project

With the environment, we can create a project in our familiar ide for initialization. Take my favorite vscode as an example (remember to install Microsoft’s official Python plug-in in advance), let’s create a new sample project in a local location first. Directory hello-dash, then open this directory as a project in vscode:
insert image description here

Create a new file app.py in the root directory of the current project, which is the main file of the simple small application we demonstrate in this article. After opening app.py, select the environment as the dash-app-dev we created earlier in the lower right corner of vscode:

picture

3 dash application infrastructure

With the app.py as the main file of the application, we can start to write the dash application code. A dash application has the following basic components:

3.1 Import of related packages

First, we need to import each module required by the sample application in this article at the beginning of the app.py file, as follows:

import dash # dash应用核心
from dash import html # dash自带的原生html组件库
import feffery_antd_components as fac # fac通用组件库
from dash.dependencies import Input, Output, State # 用于构建应用交互功能的不同角色

3.2 Instantiate the Dash() object

Next, we need to instantiate the Dash() object, and its other functional parameters will be introduced in detail in future articles:

app = dash.Dash(__name__)

3.3 Define the initial element for the dash application

On the basis of the instantiated Dash() object app, we need to assign a value to its layout property, as when our dash application is accessed, initialize the loaded page content, layout can be assigned as a single component or a function that returns a single component , usually we will directly assign an html.Div() component to it:

app.layout = html.Div()

On this basis, we can use the html.Div() component assigned to app.layout as the outermost container, and more elements that need to be loaded when other applications are initialized, we can pass them to html by nesting downwards The children parameter of .Div().

In the world of dash components, as long as a component is allowed to accept the children parameter, it can nest a single component or a list of multiple components, because the children parameter is also the first position parameter of the corresponding component, so we You can easily pass in some other components as follows. Here we take the warning prompt component in fac as an example. We pass the version information of dash and fac into its corresponding parameters:

app.layout = html.Div(
    [
        # 这里以fac中的警告提示组件为例
        # 文档地址:https://fac.feffery.tech/AntdAlert
        fac.AntdAlert(
            message='Hello Dash!',
            description=f'当前应用dash版本:{dash.__version__} fac版本:{fac.__version__}',
            showIcon=True
        )
    ]
)

3.4 Start the application

After completing the above process, let's start the current application first, add the following code at the end of app.py, where debug=True is used to enable the development and debugging mode, this is our good helper in the dash application development stage, can help us Realize convenient functions such as hot reloading and error message prompts:

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

Then switch to the root directory of the project in the terminal, which is the directory where app.py is located. On the premise of activating the dash-app-dev environment, execute the command python app.py to temporarily start our dash application. The application runs by default In http://127.0.0.1:8050, we can follow the prompts to visit in the browser:

picture

In the browser, you can see the current appearance of our dash application~

insert image description here

3.5 Adjust application style

Although our very simple dash application is running now, it looks really simple. There are many ways to adjust the style of component elements in the dash application. The most direct way is to set the relevant css style through the style parameter of the corresponding component. Attribute setting, for example, we can set a certain inner margin for the outermost html.Div() container:

insert image description here

Because we have turned on the debug=True mode, after adjusting the code, press ctrl+s to save the latest changes in app.py, the dash application being accessed in the browser will automatically refresh, which is very convenient, as you can see, at this time we The app already has padding:

insert image description here

3.6 Implement interactive functions based on callback functions

So far, our sample application is only showing static content. When we need to add interactive functions to the dash application, we need to use the core concept in the dash - the callback function. In the eyes of the callback function, each has Any attribute of the component with the unique id parameter can be arranged as a role in the callback function. The process of writing the callback function is actually playing a game of role arrangement. There are three roles in the dash, Input, Output and State, as follows Let's illustrate their respective roles with examples:

If we now need to place a button on the page, and after the user clicks the button every time, the cumulative number of clicks is displayed next to the button, the callback function can be written (the conventional callback function is essentially using @app. callback() decorates the function that defines the callback logic):
insert image description here

Among them, the content arranged in @app.callback() is translated into human words, that is, every time the nClicks property of the component whose id is button-demo is updated, the return value will be updated to the one whose id is button-demo-output through the logic defined in the function body The children attribute of the component, so the effect shown in the following animation is realized:
insert image description here

It is also possible to update multiple Output roles at the same time. For example, every time we click a button, we not only update the information on the side of the button, but also pop up a message prompt by the way, so we can modify the code to:

insert image description here

The interaction effect is as follows:
insert image description here

The fly in the ointment is that when we just access the application and do not click the button, the callback function is automatically executed first. This is because the dash application will automatically execute all the callback functions when the application is initialized by default, no matter what it is programmed Whether the Input role is updated, if you do not want this mechanism to happen, then set the parameter prevent_initial_call=True in @app.callback():
insert image description here

It can be seen that at this time, the initial access to the application will not automatically refresh relevant information:

insert image description here

Through the above simple example, we have mastered the roles of Input and Output in the dash callback function. The remaining State role is quite special. Unlike Input, which can trigger the execution of the callback function by monitoring the change of the specified attribute of the target component, State The role is used to provide auxiliary attribute values ​​in the callback function, which means that each time the callback function is triggered due to a change in the role of an Input, it will carry the attribute value corresponding to the State role into the callback function to play an auxiliary role. function of calculation.

To give a practical example, if we add an input box on the side of the button, every time the button is clicked, the input content in the input box is passed to the callback for use, and the following method can be written:
insert image description here

With the assistance of the additional State role, our application interaction effect becomes as shown in the animation below:

picture

So far, we have gotten to the basic writing method of the callback function in the dash—that is, in @app.callback(), arrange the roles in the order of Output, Input, and State, and the input parameters of the callback function (arbitrary parameter names) are the same as the arranged ones. The order of Input and State roles should be the same~

3.7 More complex application examples

After mastering the basic concepts of the dash application mentioned above, we can try to write more complex interactive application scenarios. For example, in the following simple example, we place several form input components on the page, and cooperate with fac.AntdForm( ) and fac.AntdFormItem() to quickly build the form, and realize linkage filtering with the table below through the callback function (take the pandas data frame as an example)

The complete code of the above example is as follows, please remember to install pandas before running:

# 相关包的导入
import dash  # dash应用核心
import pandas as pd
from dash import html  # dash自带的原生html组件库
import feffery_antd_components as fac  # fac通用组件库
from dash.dependencies import Input, Output, State  # 用于构建应用交互功能的不同角色


# 实例化Dash()对象
app = dash.Dash(__name__)

# 创建示例表格
demo_df = pd.DataFrame(
    {
        '字段1': [f'类别{i}' for i in range(1, 11)],
        '字段2': [10*i for i in range(10)],
        '字段3': [(pd.Timestamp('2023-01-01') + pd.Timedelta(days=i)).strftime('%Y-%m-%d')
                for i in range(10)]
    }
)

# 为dash应用定义初始元素
app.layout = html.Div(
    [
        # 这里以fac中的警告提示组件为例
        # 文档地址:https://fac.feffery.tech/AntdAlert
        fac.AntdAlert(
            message='Hello Dash!',
            description=f'当前应用dash版本:{dash.__version__} fac版本:{fac.__version__}',
            showIcon=True
        ),
        # 放置水平分割虚线
        fac.AntdDivider(isDashed=True),
        fac.AntdForm(
            [
                fac.AntdFormItem(
                    fac.AntdSelect(
                        id='field1-range',
                        options=[
                            {
                                'label': x,
                                'value': x
                            }
                            for x in demo_df['字段1'].unique()
                        ],
                        mode='multiple',
                        maxTagCount='responsive',
                        style={
                            'width': 200
                        }
                    ),
                    label='字段1'
                ),
                fac.AntdFormItem(
                    fac.AntdSlider(
                        id='field2-range',
                        min=0,
                        max=100,
                        range=True,
                        defaultValue=[0, 100],
                        style={
                            'width': 150
                        }
                    ),
                    label='字段2'
                ),
                fac.AntdFormItem(
                    fac.AntdDateRangePicker(
                        id='field3-range',
                        defaultPickerValue=demo_df['字段3'].min(),
                        style={
                            'width': 200
                        }
                    ),
                    label='字段3'
                ),
                fac.AntdButton(
                    '查询',
                    id='execute-query',
                    icon=fac.AntdIcon(
                        icon='antd-search'
                    ),
                    type='primary'
                )
            ],
            layout='inline',
            style={
                'marginBottom': 15
            }
        ),
        html.Div(id='table-result-container')
    ],
    style={
        # 这里基于css中的padding参数,设置上下内边距50像素,左右内边距100像素
        'padding': '50px 100px'
    }
)


@app.callback(
    Output('table-result-container', 'children'),
    Input('execute-query', 'nClicks'),
    [State('field1-range', 'value'),
     State('field2-range', 'value'),
     State('field3-range', 'value')]
)
def query_table(nClicks, field1_range, field2_range, field3_range):

    demo_df_copy = demo_df.copy()

    if field1_range:
        demo_df_copy.query('字段1 == @field1_range', inplace=True)

    if field2_range:
        demo_df_copy.query(f'{field2_range[0]} <= 字段2 <= {field2_range[1]}',
                           inplace=True)

    if field3_range:
        demo_df_copy.query(f'"{field3_range[0]}" <= 字段3 <= "{field3_range[1]}"',
                           inplace=True)

    if not demo_df_copy.empty:
        return fac.AntdTable(
            columns=[
                {
                    'title': column,
                    'dataIndex': column
                }
                for column in demo_df_copy.columns
            ],
            data=demo_df_copy.to_dict('records'),
            bordered=True
        )

    # 否则返回无匹配数据提示
    return fac.AntdEmpty(
        description='当前条件组合下无匹配数据'
    )


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

Reprint: https://mp.weixin.qq.com/s/Oxp_cUySuR4Tm3o-JczT1w

Guess you like

Origin blog.csdn.net/ekcchina/article/details/130425961
Recommended