<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Python】太6了!用Python快速開發(fā)數(shù)據(jù)庫入庫系統(tǒng)

          共 35729字,需瀏覽 72分鐘

           ·

          2021-04-06 09:56


          本文示例代碼已上傳至我的Github倉庫https://github.com/CNFeffery/DataScienceStudyNotes

          ?

          1 簡介

          這是我的系列教程「Python+Dash快速web應(yīng)用開發(fā)」的第十二期,在以前撰寫過的靜態(tài)部件篇(中)那期教程中,我們介紹過在Dash中創(chuàng)建靜態(tài)表格的方法。

          而在實際的使用中,我們很多時候在網(wǎng)頁中渲染的表格不僅僅是為了對數(shù)據(jù)進(jìn)行展示,還需要更多交互能力,譬如「按列排序」、「動態(tài)修改表中數(shù)值」等特性,以及對「大型數(shù)據(jù)表」「快速渲染查看」能力,諸如此類眾多的交互功能在Dash自帶的dash_table中已經(jīng)實現(xiàn)。

          而接下來的幾期,我們就將針對如何利用dash_table創(chuàng)建具有豐富交互功能的表格進(jìn)行介紹,今天介紹的是dash_table的基礎(chǔ)使用方法。

          圖1

          2 dash_table基礎(chǔ)使用

          作為Dash自帶的拓展庫,我們通過下列語句導(dǎo)入dash_table

          import dash_table

          接著像之前使用其他的Dash部件一樣,在定義layout時將dash_table.DataTable()對象置于我們定義的合適位置即可,可參考下面的例子配合pandasDataFrame來完成最簡單的表格的渲染。

          其中參數(shù)columns用于設(shè)置每一列對應(yīng)的名稱與id屬性,data接受由數(shù)據(jù)框轉(zhuǎn)化而成的特殊格式數(shù)據(jù),virtualization設(shè)置為True代表使用了「虛擬化」技術(shù)來加速網(wǎng)頁中大量表格行數(shù)據(jù)的渲染:

          ?

          app1.py

          ?
          import dash
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          import dash_table

          import seaborn as sns

          app = dash.Dash(__name__)

          # 載入演示數(shù)據(jù)集
          df = sns.load_dataset('iris')
          # 創(chuàng)建行下標(biāo)列
          df.insert(loc=0, column='#', value=df.index)

          app.layout = html.Div(
              dbc.Container(
                  dash_table.DataTable(
                      columns=[{'name': column, 'id': column} for column in df.columns],
                      data=df.to_dict('records'),
                      virtualization=True
                  ),
                  style={
                      'margin-top''100px'
                  }
              )
          )

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

          如果你對數(shù)據(jù)的展示完全沒要求,看個數(shù)就行,那上述的這套基礎(chǔ)的參數(shù)設(shè)置你就可以當(dāng)成萬金油來使用,而如果你覺得dash_table.DataTable「默認(rèn)」太丑了(大實話),那么請繼續(xù)閱讀今天的教程。

          圖2

          2.1 自定義表格基礎(chǔ)樣式

          針對DataTable所渲染出的表格的幾個基礎(chǔ)構(gòu)成部分,我們可以使用到的用于修改表格樣式的參數(shù)有style_table、style_cell、style_header、style_data等:

          • 「使用style_table來自定義表格外層容器樣式」

          參數(shù)style_table用于對整個表格最外層的容器樣式傳入css鍵值對進(jìn)行修改,一般用來設(shè)定表格的高度、寬度、周圍留白或?qū)R等屬性:

          ?

          app2.py

          ?
          import dash
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          import dash_table

          import seaborn as sns

          app = dash.Dash(__name__)

          # 載入演示數(shù)據(jù)集
          df = sns.load_dataset('iris')
          # 創(chuàng)建行下標(biāo)列
          df.insert(loc=0, column='#', value=df.index)

          app.layout = html.Div(
              dbc.Container(
                  [
                      dash_table.DataTable(
                          columns=[{'name': column, 'id': column} for column in df.columns],
                          data=df.to_dict('records'),
                          virtualization=True,
                          style_table={
                              'height''200px',
                              'margin-top''100px'
                          }
                      ),
                      html.Hr(),
                      dash_table.DataTable(
                          columns=[{'name': column, 'id': column} for column in df.columns],
                          data=df.to_dict('records'),
                          virtualization=True,
                          style_table={
                              'height''200px',
                              'margin-left''80px',
                              'width''300px'
                          }
                      ),
                      html.Hr(),
                      dash_table.DataTable(
                          columns=[{'name': column, 'id': column} for column in df.columns],
                          data=df.to_dict('records'),
                          virtualization=True,
                          style_table={
                              'height''150px',
                              'width''50%',
                              'margin-left''50%'
                          }
                      )
                  ],
                  style={
                      'background-color''#bbdefb'
                  }
              )
          )

          if __name__ == '__main__':
              app.run_server(debug=True)
          圖3
          • 「使用style_cell、style_header與style_data定義單元格樣式」

          不同于style_table,使用style_cell可以傳入css將樣式應(yīng)用到所有「單元格」,而style_headerstyle_data則更加有針對性,可分別對標(biāo)題單元格、數(shù)據(jù)單元格進(jìn)行設(shè)置:

          ?

          app3.py

          ?
          import dash
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          import dash_table

          import seaborn as sns

          app = dash.Dash(__name__)

          # 載入演示數(shù)據(jù)集
          df = sns.load_dataset('iris')
          # 創(chuàng)建行下標(biāo)列
          df.insert(loc=0, column='#', value=df.index)

          app.layout = html.Div(
              dbc.Container(
                  [
                      dash_table.DataTable(
                          columns=[{'name': column, 'id': column} for column in df.columns],
                          data=df.to_dict('records'),
                          virtualization=True,
                          style_table={
                              'height''300px'
                          },
                          style_cell={
                              'background-color''#fff9c4',
                              'font-family''Times New Romer',
                              'text-align''center'
                          }
                      ),
                      html.Hr(),
                      dash_table.DataTable(
                          columns=[{'name': column, 'id': column} for column in df.columns],
                          data=df.to_dict('records'),
                          virtualization=True,
                          style_table={
                              'height''300px'
                          },
                          style_header={
                              'background-color''#b3e5fc',
                              'font-family''Times New Romer',
                              'font-weight''bold',
                              'font-size''17px',
                              'text-align''left'
                          },
                          style_data={
                              'font-family''Times New Romer',
                              'text-align''left'
                          }
                      )
                  ],
                  style={
                      'margin-top''100px'
                  }
              )
          )

          if __name__ == '__main__':
              app.run_server(debug=True)
          圖4
          • 「條件樣式設(shè)置」

          除了像上文所演示的那樣針對某一類表格構(gòu)成元素進(jìn)行整體樣式設(shè)置外,DataTable還為我們提供了條件樣式設(shè)置,比如我們想為特殊的幾列單獨設(shè)置樣式,或者為奇數(shù)下標(biāo)與偶數(shù)下標(biāo)行設(shè)置不同的樣式,就可以使用到這一特性。

          這在DataTable中我們可以利用style_header_conditionalstyle_data_conditional來傳入列表,列表中每個元素都可看做是帶有額外if鍵值對的css參數(shù)字典,而這個if鍵值對的值亦為一個字典,其接受的鍵值對種類豐富,我們今天先來介紹column_idrow_index,它們分別用來指定對應(yīng)「id」header與整行單元格。

          參考下面這個例子,我們分別特殊設(shè)置#列的表頭與奇數(shù)行的樣式:

          ?

          app4.py

          ?
          import dash
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          import dash_table

          import seaborn as sns

          app = dash.Dash(__name__)

          # 載入演示數(shù)據(jù)集
          df = sns.load_dataset('iris')
          # 創(chuàng)建行下標(biāo)列
          df.insert(loc=0, column='#', value=df.index)

          app.layout = html.Div(
              dbc.Container(
                  [
                      dash_table.DataTable(
                          columns=[{'name': column, 'id': column} for column in df.columns],
                          data=df.to_dict('records'),
                          virtualization=True,
                          style_table={
                              'height''500px'
                          },
                          style_cell={
                              'font-family''Times New Romer',
                              'text-align''center'
                          },
                          style_header_conditional=[
                              {
                                  'if': {
                                      # 選定列id為#的列
                                      'column_id''#'
                                  },
                                  'font-weight''bold',
                                  'font-size''24px'
                              }
                          ],
                          style_data_conditional=[
                              {
                                  'if': {
                                      # 選中行下標(biāo)為奇數(shù)的行
                                      'row_index''odd'
                                  },
                                  'background-color''#cfd8dc'
                              }
                          ]
                      )
                  ],
                  style={
                      'margin-top''100px'
                  }
              )
          )

          if __name__ == '__main__':
              app.run_server(debug=True)
          圖5
          • 「隱藏所有豎直框線」

          設(shè)置參數(shù)style_as_list_view為True可以隱藏所有豎向的框線,app4設(shè)置之后的效果如下:

          圖6

          3 動手制作一個數(shù)據(jù)入庫應(yīng)用

          學(xué)習(xí)完今天的內(nèi)容之后,我們來動手寫一個簡單的數(shù)據(jù)入庫應(yīng)用,通過拖入本地csv文件以及填寫入庫表名,來實現(xiàn)對上傳數(shù)據(jù)的預(yù)覽與數(shù)據(jù)庫導(dǎo)入,后端會自動檢查用戶輸入的數(shù)據(jù)表名稱是否合法,并自動檢測上傳csv文件的文件編碼。

          下面就是該應(yīng)用工作時的情景,其中因為test表在庫中已存在,所以會被檢測出不合法:

          圖7

          而當(dāng)上傳的數(shù)據(jù)表行數(shù)較多時,右下角會自動出現(xiàn)分頁部件,我們將在下一期中進(jìn)行討論,完整代碼如下:

          ?

          app5.py

          ?
          import dash
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          from dash.dependencies import Input, Output, State
          import dash_table
          import dash_uploader as du

          import re
          import os
          import pandas as pd
          from sqlalchemy import create_engine
          import cchardet as chardet # 用于自動識別文件編碼

          postgres_url = 'postgresql://postgres:CUDLCUDL@localhost:5432/Dash'
          engine = create_engine(postgres_url)

          app = dash.Dash(__name__)

          du.configure_upload(app, 'upload')

          app.layout = html.Div(
              dbc.Container(
                  [
                      du.Upload(
                          id='upload',
                          filetypes=['csv'],
                          text='點擊或拖動文件到此進(jìn)行上傳!',
                          text_completed='已完成上傳文件:',
                          cancel_button=True,
                          pause_button=True),
                      html.Hr(),
                      dbc.Form(
                          [
                              dbc.FormGroup(
                                  [
                                      dbc.Label("設(shè)置入庫表名", html_for="table-name"),
                                      dbc.Input(
                                          id='table-name',
                                          autoComplete='off'
                                      ),
                                      dbc.FormText(
                                          "表名只允許包含大小寫字母、下劃線或數(shù)字,且不能以數(shù)字開頭,同時請注意表名是否與庫中現(xiàn)有表重復(fù)!", color="secondary"
                                      ),
                                      dbc.FormFeedback(
                                          "表名合法!", valid=True
                                      ),
                                      dbc.FormFeedback(
                                          "表名不合法!",
                                          valid=False,
                                      ),
                                  ]
                              ),
                              dbc.FormGroup(
                                  [
                                      dbc.Button('提交入庫', id='commit', outline=True)
                                  ]
                              )
                          ],
                          style={
                              'background-color''rgba(224, 242, 241, 0.4)'
                          }
                      ),
                      dbc.Spinner(
                          [
                              html.P(id='commit-status-message', style={'color''red'}),
                              dbc.Label('預(yù)覽至多前10000行', html_for='uploaded-table'),
                              dash_table.DataTable(
                                  id='uploaded-table',
                                  style_table={
                                      'height''400px'
                                  },
                                  virtualization=True,
                                  style_as_list_view=True,
                                  style_cell={
                                      'font-family''Times New Romer',
                                      'text-align''center'
                                  },
                                  style_header={
                                      'font-weight''bold'
                                  },
                                  style_data_conditional=[
                                      {
                                          'if': {
                                              # 選中行下標(biāo)為奇數(shù)的行
                                              'row_index''odd'
                                          },
                                          'background-color''#cfd8dc'
                                      }
                                  ]
                              )
                          ]
                      )
                  ],
                  style={
                      'margin-top''30px'
                  }
              )
          )


          @app.callback(
              [Output('table-name''invalid'),
               Output('table-name''valid')],
              Input('table-name''value')
          )
          def check_table_name(value):
              ''''
              檢查表名是否合法
              '''

              if value:

                  # 查詢庫中已存在非系統(tǒng)表名
                  exists_table_names = (
                      pd
                          .read_sql('''SELECT tablename FROM pg_tables''', con=engine)
                          .query('~(tablename.str.startswith("pg") or tablename.str.startswith("sql_"))')
                  )

                  if (re.findall('^[A-Za-z0-9_]+$', value)[0].__len__() == value.__len__()) \
                          and not re.findall('^\d', value) \
                          and value not in exists_table_names['tablename'].tolist():
                      return FalseTrue

                  return TrueFalse

              return dash.no_update


          @app.callback(
              Output('commit-status-message''children'),
              Input('commit''n_clicks'),
              [State('table-name''valid'),
               State('table-name''value'),
               State('upload''isCompleted'),
               State('upload''fileNames'),
               State('upload''upload_id')]
          )
          def control_table_commit(n_clicks,
                                   table_name_valid,
                                   table_name,
                                   isCompleted,
                                   fileNames,
                                   upload_id)
          :

              '''
              控制已上傳表格的入庫
              '''

              if all([n_clicks, table_name_valid, table_name, isCompleted, fileNames, upload_id]):
                  uploaded_df = pd.read_csv(os.path.join('upload', upload_id, fileNames[0]),
                                            encoding=chardet.detect(open(os.path.join('upload', upload_id, fileNames[0]),
                                                                         'rb').read())['encoding'])

                  uploaded_df.to_sql(table_name, con=engine)

                  return '入庫成功!'

              return dash.no_update


          @app.callback(
              [Output('uploaded-table''data'),
               Output('uploaded-table''columns')],
              Input('upload''isCompleted'),
              [State('upload''fileNames'),
               State('upload''upload_id')]
          )
          def render_table(isCompleted, fileNames, upload_id):
              '''
              控制預(yù)覽表格的渲染
              '''

              if isCompleted:
                  uploaded_df = pd.read_csv(os.path.join('upload', upload_id, fileNames[0]),
                                            encoding=chardet.detect(open(os.path.join('upload', upload_id, fileNames[0]),
                                                                         'rb').read())['encoding']).head(10000)

                  uploaded_df.insert(0'#', range(uploaded_df.shape[0]))

                  return uploaded_df.to_dict('record'), [{'name': column, 'id': column} for column in uploaded_df.columns]

              return dash.no_update


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

          以上就是本文的全部內(nèi)容,歡迎在評論區(qū)與我進(jìn)行討論~


          往期精彩回顧





          本站qq群851320808,加入微信群請掃碼:

          瀏覽 42
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线免费小黄片 | 国产V亚洲V日韩V欧美V | 九七无码视频 | 亚洲第一页中文 | 亚洲无码中文字幕在线播放 |