flask
flask_ext
python
SQLAlchemy
官方文件:
目前來說,只要在企業內要自建一個系統就一定會牽扯到對資料庫的操作,如果每一個操作都寫著一句SQL語法,那維護起來版面著實嚇人,ORM的出現幫忙程式設計師簡化了大量這類基礎SQL語法的操作,也可以減少SQL injection
攻擊(SQL injection)。
Flask並沒有限定一定要使用SQLAlchemy
這類ORM操作的套件,但是SQLAlchemy
可以搭配sqlite、Mysql、PostgreSQL、MSSql、Oracle,這已經涵蓋市面上常用的資料庫。而flask-sqlachemy
是為了簡化Flask開發人員操作而出現的套件,它適度的包裝了SQLAlchemy
。
直觀來看,透過ORM我們可以將資料庫當做物件來操作,這讓開發人員不用花心思的去處理資料庫的DDL(Create, Drop…)、DML(Select, Delete, Update, Insert..)。如果你開發過MVC
那就一定很了解這一塊就是MODEL
。
另外,強烈建議一定要去閱讀SQLAchemy相關文件!
pip install flask-sqlalchemy
安裝flask-sqlalchemy
的時候會自動下載相依套件sqlachemy
,不用特別另外安裝。
實務上我們會將Model
另外設置一個Python文件管理,但是這是一個單題的說明,不會這麼麻煩,只要知道有這麼一件事就可以。
以下是model.py
文件
from flask import Flask
# from flask.ext.sqlalchemy import SQLAlchemy<--新版取消了
from flask_sqlalchemy import SQLAlchemy
import os
# 取得目前文件資料夾路徑
pjdir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
# 新版本的部份預設為none,會有異常,再設置True即可。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 設置sqlite檔案路徑
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + \
os.path.join(pjdir, 'data.sqlite')
db = SQLAlchemy(app)
#...下略...#
利用我們在實作中的專案來簡單調整為這次的範例,sqlite
是檔案式資料庫,不需要連線ip,只要知道檔案所在即可,這在android
手機上很常見的應用。
既然ORM是把資料庫當物件來操作,那代表就需要建置類別,不同於sqlachemy
,flask-sqlachemy
簡化了整個操作,在import進來的時候,它已經將sqlalchemy
與sqlalchemy.orm
通通載入並且提供了Model
類別。
#...接上...#
class User(db.Model):
__tablename__ = 'Users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
第19行:繼承稍早所初始化的db.Model
完成資料庫的設置之後需要至命令模式下初始化資料庫,如下:
>>> from model_user import db
>>> db.create_all()
透過指令產生資料庫之後,就會看到在專案內多了一個data.sqlite
檔案,如下圖:
初始化資料庫之後,我們就可以驗證自己建置的ORM是否可以正常的工作,只需要在Python shell命令中去import新增的類別操作,如下:
from model_user import User
# 實作類別
admin = User('admin', 'admin@abc.com')
user1 = User('user1', 'user1@abc.com')
# 寫入資料
db.session.add(admin)
db.session.add(user1)
db.session.commit()
先確認一下自己的資料庫是乾淨的:
commit
之後,確實的寫入資料:
也可以確認一下自己__repr__
的回傳,如下:
>>> admin
<User 'admin'>
>>> user1
<User 'user1'>
透過這個案例可以感受到ORM帶來的便利,我們完全沒有寫到任何一句SQL Statement就完成寫入的工作。
在flask-sqlalchemy
內已經透過Model
類(在宣告User
時繼承的db.Model
)提供了query
的method,因此可以直接透過該類別來查詢,如下:
# 全部取回
>>> all_users = User.query.all()
>>> all_users
[<User 'admin'>, <User 'user1'>]
查看一下型別
>>> type(all_users)
<class 'list'>
利用取回的資料找尋使用者資料
>>> all_users[1]
<User 'user1'>
>>> all_users[1].id
2
>>> all_users[1].username
'user1'
>>> all_users[1].email
'user1@abc.com'
透過條件尋找使用者
>>> query_admin = User.query.filter_by(username='admin').first()
>>> query_admin
<User 'admin'>
如果沒有first?
>>> query_admin = User.query.filter_by(username='admin')
>>> query_admin
<flask_sqlalchemy.BaseQuery object at 0x03631E90>
# 透過delete刪除
>>> db.session.delete(admin)
>>> db.session.commit()
# commit之後查詢一下目前所有使用者
>>> user_all = User.query.all()
>>> user_all
[<User 'user1'>]
# 變更使用者名稱
>>> admin.username='newAdmin'
>>> db.session.add(admin)
>>> db.session.commit()
>>> all_user = User.query.all()
>>> all_user
[<User 'newAdmin'>, <User 'guest'>]
在查詢之後可直接修正屬性再透過db.session.add
的方式直接做更新
這是對SQLAlchemy
的初探,我們所用的不過就是它的百分之一的功能,但也有前輩說過,再強大的軟體,也許常用的也只有那百分之一而以,而這百分之一也讓我們感受到ORM所帶來的便利性。
後續尚有資料庫的關聯設置以及其它QUERY的說明,記得繼續學習。
Flask-SQLAlchemy_關聯:Flask實作_ext_02_Flask-SQLAlchemy_關聯
Flask-SQLAlchemy_Query:Flask實作_ext_18_Flask-SQLAlchemy_Query
SQLite
有圖形化介面可以使用,個人使用sqlitebrowser
不同的資料庫連接有不同的相依套件需要下載,像Oracel
就需要cx_Oracle
,更詳細部份可參考官方文件說明。
SQLAlchemy | python | 說明 |
---|---|---|
Integer | int | 整數(32bit) |
SmallInteger | int | 整數(16bit) |
BigInteger | int | 整數(不限精度) |
Float | float | 浮點數 |
Numeric | decimal.Decimal | 定點數 |
String | str | 文字 |
Text | str | 長字串 |
Unicode | unicode | |
UnicodeText | unicode | |
Boolean | bool | |
Date | datetime.date | |
Time | datetime.time | |
DateTime | datetime.datetime | |
PickleType | object | 序列化文件 |
LargeBinary | str | 二進制文件 |
參數 | 用途 |
---|---|
primary_key | 主鍵 |
unique | 唯一值 |
index | 設置索引 |
nullable | 允許null |
default | 設置欄位預設值 |
方法 | 說明 |
---|---|
all() | 回傳所有結果 |
first() | 回傳第一個結果,沒有就回傳None |
first_or_404() | 應用如下說明 |
get() | 利用指定主鍵查詢,沒有就回傳None |
get_or_404() | 同下說明 |
count() | 回傳查詢結果數量 |
paginate() | 分頁 |
在view中如果希望搜尋不到值的時候拋出404而不是None的話,可透過get_or_404()
、first_or_404()
來設置,再利用app_errorhandler
來做異常處理。
@app.route('/user/<username>')
def get_user(username):
user = User.query.filter_by(username=username).first_or_404()
return render_template('Yourpage.html', user=user)