純 Python 輕鬆開發在線留言板!
本文示例代碼已上傳至我的
Github
倉庫 https://github.com/CNFeffery/DataScienceStudyNotes
1 簡介
這是我的系列教程**「Python+Dash 快速 web 應用開發」**的第十七期,在之前的各期教程中,我們針對Dash
中各種基礎且常用的概念展開了學習,但一直沒有針對與數據庫之間交互進行專門的介紹,只是在某些示例中利用pandas
、SQLAlchemy
等工具簡陋地操作數據庫。
而在今天的教程中,我就將帶大家學習在Dash
中利用簡單好用的ORM
庫peewee
,快速高效地將數據庫整合進Dash
應用中。
圖 1
2 利用 peewee 在 Dash 中整合數據庫
說起peewee
,很多使用過 ORM(Object Relational Mapping,對象關係映射)工具的朋友都聽說過,它跟SQLAlchemy
等框架從功能上看都大同小異,目的都是爲了**「不寫 SQL」**,而是利用面向對象編程的方式,在Python
中實現常用的SQL
功能。
圖 2
peewee
雖然相比SQLAlchemy
等重型的ORM
框架已經輕量很多了,但內容還是非常豐富,我們今天就針對一些典型場景,展示一下其與Dash
應用如何相互結合。
2.1 創建數據表
利用peewee
構建數據表,需要定義相應的Model
類,在類中構建的屬性即對應表中的字段,並且在Meta
類中定義其他的一些屬性,譬如下面的例子我們就以最簡單的SQLite
數據庫爲例:
❝
model1.py
❞
from peewee import SqliteDatabase, Model
from peewee import CharField, IntegerField, DateTimeField
from datetime import datetime
# 關聯數據庫,對於sqlite數據庫若不存在則會直接創建
db = SqliteDatabase('17 整合數據庫/model1.db')
class Model1(Model):
# 用戶名爲字符型,並設置唯一性約束
username = CharField(unique=True)
# 用戶等級設定爲整數型
level = IntegerField()
# 用戶加入時間爲時間日期類型
join_datetime = DateTimeField()
class Meta:
database = db # 指定數據庫
table_name = 'user_info' # 自定義數據表名,不設置則自動根據類名推導
# 創建數據表,若對應數據庫中已存在此表,則會跳過
db.create_tables([Model1])
上述的代碼在執行之後,便會在關聯到的SQLite
數據庫中創建對應的表:
圖 3
而除了最簡單的SQLite
之外,peewee
還支持MySQL
、PostgreSQL
,你可以在http://docs.peewee-orm.com/en/latest/peewee/database.html
查看更多使用示例,關於更多有關Model
創建的知識可以參考http://docs.peewee-orm.com/en/latest/peewee/models.html
。
2.2 向表中新增記錄
在數據表創建完成之後,我們第一件事當然是要向表中插入數據,這在peewee
中操作非常簡單:
- 「插入單條數據」
在peewee
中向表中插入單條記錄可以使用create()
方法:
# 創建單條記錄
Model1.create(username='張三', level=6, join_datetime=datetime(2020, 1, 1, 10, 28, 45))
Model1.create(username='李四', level=1, join_datetime=datetime(2020, 5, 1, 10, 28, 45))
執行完上述命令後旋即會更新到數據庫表中:
圖 4
- 「插入多條數據」
在peewee
中批量插入數據可以使用insert_many()
方法傳入對應每行內容的字典列表,記得最後要跟着執行execute()
方法纔會真正向數據庫執行:
# 批量插入數據
(
Model1
.insert_many([
{'username': '王五', 'level': 3, 'join_datetime': datetime(2020, 3, 1, 10, 28, 45)},
{'username': '趙六', 'level': 2, 'join_datetime': datetime(2020, 4, 1, 10, 28, 45)}])
.execute()
)
圖 5
2.3 從表中刪除數據
對於已存在數據的表,進行數據刪除可以使用到delete()
方法其後再鏈式上where()
來聲明判斷條件,最後同樣跟上execute()
方法執行即可,如果要清空整張表則不用加where()
,譬如我們要刪除level
小於 3 的記錄:
# 刪除level小於3的記錄
Model1.delete().where(Model1.level < 3).execute()
圖 6
更多關於peewee
數據刪除的知識可以參考官方文檔http://docs.peewee-orm.com/en/latest/peewee/querying.html#deleting-records
部分內容。
2.4 對錶中數據進行更新
作爲**「增刪改查」**中非常重要的**「改」**,在peewee
中實現也是非常的方便,基礎的用法是配合update()
與where()
如下面的例子那樣:
# 修改username爲張三的記錄值level字段爲8
Model1.update(level=8).where(Model1.username == '張三').execute()
圖 7
更多內容可參考官方文檔http://docs.peewee-orm.com/en/latest/peewee/querying.html#updating-existing-records
。
2.5 對錶中數據進行查詢
作爲**「增刪改查」**中使用頻次最高的**「查」**,在peewee
中涉及到的知識內容非常之龐大,但基礎的格式都是利用select()
方法,常用的有以下方式:
# 獲取查詢結果方式1:
query_results = Model1.select().where(Model1.level > 2).execute()
for query_result in query_results:
print(query_result.username)
圖 8
# 獲取查詢結果方式2:
query_results = Model1.select().where(Model1.level > 2).dicts()
list(query_results)
圖 9
而有關跨表連接等進階的查詢操作,請參考官方文檔http://docs.peewee-orm.com/en/latest/peewee/query_examples.html#query-examples
。
2.6 基於已存在的表逆向生成 Model
如果你的數據庫表已然存在,又希望生成相應的Model
類,peewee
提供了命令行工具幫我們做這件事,以SQLite
爲例:
python -m pwiz -e sqlite model1.db >model2.py
自動生成的model2.py
代碼如下,在這個基礎上我們可以進一步的優化修改:
from peewee import *
database = SqliteDatabase('model1.db')
class UnknownField(object):
def __init__(self, *_, **__): pass
class BaseModel(Model):
class Meta:
database = database
class UserInfo(BaseModel):
join_datetime = DateTimeField()
level = IntegerField()
username = CharField(unique=True)
class Meta:
table_name = 'user_info'
而更多關於peewee
利用pwiz
生成Model
類的參數和用法可參考官方文檔http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#pwiz-a-model-generator
。
3 peewee 配合 Dash 實現在線留言板功能
get
到peewee
的常用基礎用法之後,我們回到本文的重點——結合Dash
整合數據庫,要實現的功能很簡單,就是實現一個在線留言板,每個訪問應用的用戶都可以在填寫若干信息後,發表自己的留言,其他用戶後續訪問可以看到前面用戶發表過的留言信息。
爲了方便演示,我選擇SQLite
作爲示例數據庫,首先我們需要構建一個model.py
來設計表模型,來存放每條留言信息,並自定義一些功能函數:
❝
model.py
❞
from peewee import SqliteDatabase, Model
from peewee import CharField, DateTimeField, TextField
from datetime import datetime
db = SqliteDatabase('17 整合數據庫/message_board.db')
class MessageBoard(Model):
nickname = CharField()
pub_date = DateTimeField()
message_content = TextField()
class Meta:
database = db # 指定數據庫
table_name = 'message_board' # 自定義數據表名,不設置則自動根據類名推導
db.create_tables([MessageBoard])
# 新增留言記錄
def submit_new_message(nickname, message_content):
MessageBoard.create(
nickname=nickname,
pub_date=datetime.now(),
message_content=message_content
)
# 獲取全部留言記錄
def fetch_all_message():
return list(MessageBoard.select().dicts())
接着我們只需要在對應Dash
應用的app.py
中調用model.py
中的相關功能即可,效果如下(動圖錄制有些花屏,大家可以自己運行嘗試,效果更佳):
圖 10
❝
app.py
❞
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
from model import MessageBoard, submit_new_message, fetch_all_message
app = dash.Dash(__name__)
app.layout = html.Div(
dbc.Container(
[
html.Div(style={'height': '20px'}),
html.H2('Dash示例留言板'),
dbc.Container(
id='history-message',
style={
'paddingTop': '50px',
'width': '70%',
'height': '70%',
'overflowY': 'auto',
'backgroundColor': '#fafafa'
}
),
dbc.Container(
dbc.Row(
[
dbc.Col(
dbc.Input(placeholder='輸入暱稱:', id='nickname', style={'width': '100%'}),
width=3,
style={
'padding': 0
}
),
dbc.Col(
dbc.Input(placeholder='輸入留言內容:', id='message', style={'width': '100%'}),
width=7,
style={
'padding': 0
}
),
dbc.Col(
dbc.Button('提交', id='submit', color='primary', block=True),
width=2,
style={
'padding': 0
}
)
]
),
style={
'paddingTop': '10px',
'width': '70%',
}
)
],
style={
'height': '800px',
'boxShadow': 'rgb(0 0 0 / 20%) 0px 13px 30px, rgb(255 255 255 / 80%) 0px -13px 30px',
'borderRadius': '10px'
}
),
style={
'paddingTop': '50px'
}
)
@app.callback(
Output('history-message', 'children'),
Input('submit', 'n_clicks'),
[State('nickname', 'value'),
State('message', 'value')]
)
def refresh_message_board(n_clicks, nickname, message):
if nickname and message:
submit_new_message(nickname, message)
return [
html.Div(
[
html.Strong(record['nickname']),
html.Span(' '),
html.Em(record['pub_datetime'].strftime(format='%Y-%m-%d %H:%M:%S')),
html.Br(),
html.P(record['message_content'])
]
)
for record in fetch_all_message()
]
if __name__ == '__main__':
app.run_server(debug=True)
有關peewee
的內容非常豐富,想要完全記住不太現實,大家可以養成多查官網http://docs.peewee-orm.com/en/latest/
的習慣,內容非常詳細生動,給官方點個贊!
以上就是本文的全部內容,歡迎在評論區發表你的意見和想法。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/KWgqTK30Co6bTku8Jn76Ow