Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2
本文介紹了第一次在Flask框架中操作SQLite3數據庫的測試,參考了官網的文檔Using SQLite 3 with Flask,直接使用了里面定義
的幾個函數:init_db、get_db、close_connection、make_dicts,另外,自己編寫了視圖(View)函數實現添加、讀取操作。
本測試項目的目標
-使用建模文件初始化數據庫成功
-連接數據庫成功
-關閉數據庫成功
-添加數據成功
-讀取數據成功,並成功返回到頁面
測試步驟
1.建立空的SQLite3數據庫文件 和 數據庫建模文件
前面一篇關於SQLite3的文章有介紹,使用sqlite3.exe即可;
數據庫建模文件,參考SQLite官方文檔SQL As Understood By SQLite建立;
下面是我的建模文件內容:
1 DROP TABLE IF EXISTS post; 2 CREATE TABLE post ( 3 id INTEGER PRIMARY KEY AUTOINCREMENT, 4 body VARCHAR(500) NOT NULL, 5 created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 6 );
如果原數據庫存在,就刪除,然后建立新的。
數據表post,包括id、body、created三個字段,其中,body字段為提交的消息,created為消息存放到數據庫的時間。
建立好的數據庫文件和建模文件放到項目的db文件夾下:
說明,數據庫文件和建模文件不一定要放到db文件夾下,也可以放到Flask項目的根目錄下(Q:是否可以放到項目之外呢?不建議。),只要程序中把相關路徑輸入正確即可。
2.編寫Flask項目文件main.py(單模塊項目)
將文檔Using SQLite 3 with Flask中的一些代碼拷貝到many.py中。
1 from flask import * # 導入flask模塊下的所有元素 2 import sqlite3 # 導入sqlite3模塊 3 4 app = Flask('Posts') # 建立Flask應用 5 6 DATABASE = 'db/posts.db' # 數據庫文件地址 7 DATABASE_INIT_FILE = 'db/init.sql' # 數據庫建模文件地址 8 9 # init_db() 10 def init_db(): # 此函數要使用 數據庫建模文件 初始化數據庫:建立post表(Initial Schemas)。此函數在命令行中使用,僅一次,再次使用會刪除數據庫中已有數據。 11 with app.app_context(): # 官網文檔說了原因:不是在Web應用中使用,而是在Python Shell中使用時需要此語句(Connect on Demand)。 12 db = get_db() 13 with app.open_resource(DATABASE_INIT_FILE, mode='r') as f: # with語句用法! 14 db.cursor().executescript(f.read()) # 執行建模文件中的腳本 15 db.commit() # 提交事務 16 17 # make_dicts() 18 def make_dicts(cursor, row): # 將查詢返回的數據的轉換為字典類型,這樣會跟方便使用。此函數會在get_db()函數中用到,賦值給db.row_factory。 19 return dict((cursor.description[idx][0], value) 20 for idx,value in enumerate(row)) 21 22 # get_db() 23 def get_db(): # 獲取數據庫連接 24 db = getattr(g, '_database', None) # g對象時一個Flask應用的公共對象(和request、session一樣),用於存儲用戶的數據——整個應用共享! 25 if db is None: 26 db = g._database = sqlite3.connect(DATABASE) # 建立數據庫連接 27 db.row_factory = make_dicts # 轉換默認的查詢數據類型為字典類型,也可以使用sqlite3.Row 28 return db # 返回數據庫連接,可能返回為None 29 30 # close_connection() 31 @app.teardown_appcontext # 這個裝飾器用於實現在請求的最后自動關閉數據庫連接的功能 32 def close_connection(exception): # 關閉數據庫連接 33 db = getattr(g, '_database', None) 34 if db is not None: 35 db.close()
說明,在謄寫代碼過程中,把cursor.description寫錯了,直到最后運行程序才發現了錯誤。
以上,初始化數據庫——只執行一次、獲取數據庫連接、關閉數據庫連接的程序都有了。接下來,建立一個視圖函數測試數據庫連接、關閉數據庫連接是否正常執行。
注意,在此時之前需要再get_db、close_connection函數中添加調試語句,print或者app.logger都可以。
1 @app.route('/testdb') 2 def testdb(): 3 get_db() 4 return "After test"
然后,啟動Flask項目,使用瀏覽器訪問/testdb,檢查項目命令行即可看到添加的調試語句——提示錯誤就繼續修改。
3.使用 建模文件 初始化 數據庫文件
這個時候需要用到上面的init_db()函數了。
在文檔Using SQLite 3 with Flask的Initial Schemas中有介紹,將Flask項目模塊的init_db()函數導入,再執行即可。
下面是我的測試情況:成功 按照建模文件 建立 數據表post
注意,在Python Shell執行上面的命令時,需要保證當前目錄為Flask項目所在目錄。
4.建立測試項目需要視圖函數(View functions)
本測試項目需要實現發布消息、展示消息的功能(但並沒有做到同一個頁面上),因此,建立了三個視圖函數來實現目標:
4.1 home()
首頁,返回一個模板用於添加post。
此模板文件僅包含靜態內容,因此,render_template只有一個參數。
1 # path: / 2 # show posts 3 @app.route('/') 4 def home(): 5 return render_template('temp.html')
模板文件主要內容:定義表單,action為“pureadd”
1 <form action="pureadd" method="post"> 2 <textarea name="newpost" style="width:200px;height:100px;" maxlength="500"></textarea><br /> 3 <input type="submit" value="添加" /> 4 </form> 5 <a href="/pureshow">展示帖子</a><br />
頁面如下:
4.2 pureadd()
一個單純地(pure)用於添加一條post到數據庫的視圖函數,會對參數進行校驗、發生錯誤時會返回錯誤的信息等。
僅支持POST方法的請求。
此視圖的返回信息中還包括跳轉到添加頁面、展示頁面的鏈接。
1 # pure add page for test 2 @app.route('/pureadd', methods=['POST']) 3 def pureadd(): 4 # step 1. get the new post and check the data 5 newp = '' 6 try: 7 newp = request.form['newpost'] 8 except: 9 return 'ERROR: Invalid form parameters!' 10 11 print('newp = "', newp, '"') 12 13 newp2 = newp.strip() # 清理post兩遍的空格,然后賦值給新變量——此時舊變量沒有改變 14 15 if newp2 == '': 16 return 'Warning: New post is empty!<br/>' \ 17 '<a href="/">繼續添加</a><br/>' \ 18 '<a href="/pureshow">展示帖子</a><br />' 19 20 # step 2.write the new post into database 21 sqlmode = 'INSERT INTO post(body) VALUES(?)' # 添加數據的SQL語句,占位符使用問號(?)。需要注意的是,如果是MySQL,占位符是百分號(%)。 22 try: 23 db = get_db() 24 cursor = db.cursor() 25 cursor.execute(sqlmode, (newp2,)) 26 cursor.close() # 關閉cursor。Q:是否一定要關閉呢?不關閉有什么影響? 27 db.commit() # 需要commit,否則,數據不會更新到數據庫 28 except Exception as e: 29 return '<span style="color:red;">INFO: New post added failed <br/> %s</span><br/>' \ 30 '<a href="/">繼續添加</a><br/>' \ 31 '<a href="/pureshow">展示帖子</a><br />' % str(e) 32 else: 33 return 'INFO: New post added <br/><pre>[%s]</pre><br/>' \ 34 '<a href="/">繼續添加</a><br/>' \ 35 '<a href="/pureshow">展示帖子</a><br />' % newp
成功添加一條數據:
數據庫中顯示添加的數據:
4.3 pureshow()
此視圖函數用於 展示數據庫中的數據。
將查詢到的數據直接返回到 模板文件showall.html 中。
注意,需要提一下前面get_db()函數中的設置db.row_factory為make_dicts。如果沒有這個賦值的話,模板文件的解析數據方式將會改變。
1 # pure show page for test 2 @app.route('/pureshow') 3 def pureshow(): 4 sqlmode = "SELECT * FROM post ORDER BY created DESC" 5 rv = [] 6 try: 7 db = get_db() 8 cursor = db.execute(sqlmode) 9 rv = cursor.fetchall() 10 cursor.close() 11 except Exception as e: 12 print(e) 13 abort(500) 14 else: 15 return render_template('showall.html', posts=rv)
模板文件showall.html的主要內容:使用for循環將pureshow()函數返回的內容展示出來
1 <div id="postslist"> 2 {% for post in posts %} 3 <div class="post_item" id="post{{ post.id }}"> 4 {{ post.body }}<br/> 5 {{ post.created }} 6 </div> 7 {% endfor %} 8 </div> 9 <a href="/">繼續添加</a>
/pureshow頁面展示內容如下:
注意,數據庫中保存的時間為UTC時間,在實際應用中,展示出來時還需要添加對應的時差。
參考鏈接
后續
上面的方法很簡單,在Flask提供的擴展中,有一個叫做SQLAlchemy的,使用它可以更高效地操作各種數據庫,所以,下一步就是學習並使用它了。
官方文檔SQLAlchemy in Flask中有介紹,看過一遍了,現在,該實踐了。
前面做的項目都是基於單個的模型文件的,后面需要升級:基於package的方式、使用Blueprint,這兩個是重點啊!
在官網的Tutorial會有關於SQLAlchemy、Blueprint的介紹,也是需要參考的。
Flask,還需要以周計的時間才能熟練使用啊。
自己沒有做過完整的Web應用,在URL設計等方面存在一些挑戰,因此,這個測試項目才會如此simple。
本來還想實現用戶登錄、退出等“稍微復雜”的功能的——最初的想法,最后都只能放棄了。
我想,在熟悉了SQLAlchemy、Blueprint后,Web開發的功力會有很大提高的。
對了,還有就是 怎么提供數據接口給前端,比如RESTful API等,都是需要熟練的。