Flask-SQLAlchemy庫讓flask更方便的使用SQLALchemy,是一個強大的關系形數據庫框架,既可以使用orm方式操作數據庫,也可以使用原始的SQL命令.
Flask-Migrate 是一個數據遷移框架,需要通過Flask-script庫來操作.
一.配置Flask-SQLAlchemy
程序使用的數據庫地址需要配置在SQLALCHEMY_DATABASE_URI中,SQLALchemy支持多種數據庫,配置格式如下:
Postgres:
postgresql://scott:tiger@localhost/mydatabase
MySQL:
mysql://scott:tiger@localhost/mydatabase
Oracle:
oracle://scott:tiger@127.0.0.1:1521/sidname
SQLite:
sqlite:////absolute/path/to/foo.db
db是SQLALchemy類的實例,表示程序使用的數據庫,為用戶提供Flask-SQLALchemy的所有功能
from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__) #配置數據庫地址 app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' #該配置為True,則每次請求結束都會自動commit數據庫的變動 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app) #也可以db = SQLAlchemy() db.init_app(app)
二.定義模型
Flask-SQLALchemy使用繼承至db.Model的類來定義模型,如:
class User(db.Model, UserMixin):#UserMixin是Flask-Login庫中所需要的 __tablename__ = 'users' #每個屬性定義一個字段 id = db.Column(db.Integer,primary_key=True) username = db.Column(db.String(64),unique=True)
password = db.Column(db.String(64))
def __repr__(self): return '<User %r>' % self.username
定義完需要在Python Shell中導入db,調用db.create_all()來創建數據庫
(1)常用字段選項:
primary_key 設置主鍵
unique 是否唯一
index 是否創建索引
nullable 是否允許為空
default 設置默認值,可以傳入函數的引用 如傳入 datetime.datetime.utcnow 則每次創建時時間都是最新時間
三.增刪查改
(1) 插入數據:
from app.models import User from app import db #創建一個新用戶 u = User() u.username = 'abc' u.password = 'abc'
#將用戶添加到數據庫會話中 db.session.add(u)
#將數據庫會話中的變動提交到數據庫中,如果不Commit,數據庫中是沒有改動的 db.commit()
(2)查找數據:
#返回所有用戶保存到list中 user_list = User.query.all() #查找username為abc的第一個用戶,返回用戶實例 u = User.query.filter_by(username='abc').first() #模糊查找用戶名以c結尾的所有用戶 user_list = User.query.filter(username.endswith('c')).all() #查找用戶名不是abc的用戶 u = User.query.filter(username != 'abc').first()
(3)刪除數據:
user = User.query.first()
db.session.delete(user)
db.session.commit()
(4)修改數據:
u = User.query.first() u.username = 'sb' db.session.commit()
四.一對多關系
我的理解是:在多的一邊定義外鍵,而relathonship()函數是用來建立關系的,可以只在一邊定義,也可以兩邊都使用(只在一邊使用時加上了backref選項等同於兩邊都使用)
class Person(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50)) #backref將在Address表中創建個名為persons的Person引用,之后可以使用address.persons訪問這個地址的所有人 addresses = db.relationship('Address', backref='persons', lazy='dynamic') class Address(db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(50)) #在多的一邊使用db.ForeignKey聲明外鍵 person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
五.多對多關系
多對多關系可以分解為原表和關聯表之間兩個多對一關系,如下代碼建立了學生與所選課程之間的關系:
#創建關聯表,兩個字段的外鍵是另兩個表,一個學生對應多個關聯表,一個關聯表對應多個課程 registrations = db.Table('registrations', db.Column('student_id',db.Integer,db.ForeignKey('students.id')), db.Column('class_id',db.Integer,db.ForeignKey('classes.id')) ) class Student(db.Model): __tablename__ = 'students' id = db.Column(db.Integer,primary_key=True,) name = db.Column(db.String) classes = db.relationship('Class', secondary = registrations, #關聯表,只需要在一個表建立關系,sqlalchemy會負責處理好另一個表 backref = db.backref('students',lazy='dynamic'), lazy = 'dynamic') class Class(db.Model): __tablename__ = 'classes' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String)
多對多的使用:
#學生1增加一門選課 student1.classes.append(class1) #學生1退選class1 student1.classes.remove(class1) #學生1所選課程,由於指定了lazy='dynamic'所以沒有直接返回列表,而需要使用.all() student1.classes.all()
六.分頁導航
Flask-SQLALchemy的Pagination對象可以方便的進行分頁,
對一個查詢對象調用pagenate(page, per_page=20, error_out=True)函數可以得到pagination對象,第一個參數表示當前頁,第二個參數代表每頁顯示的數量,error_out=True的情況下如果指定頁沒有內容將出現404錯誤,否則返回空的列表
#從get方法中取得頁碼 page = request.args.get('page', 1, type = int) #獲取pagination對象 pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=10, error_out = False) #pagination對象的items方法返回當前頁的內容列表 posts = pagination.items
pagination對象常用方法:
has_next :是否還有下一頁
has_prev :是否還有上一頁
items : 返回當前頁的所有內容
next(error_out=False) : 返回下一頁的Pagination對象
prev(error_out=False) : 返回上一頁的Pagination對象
page : 當前頁的頁碼(從1開始)
pages : 總頁數
per_page : 每頁顯示的數量
prev_num : 上一頁頁碼數
next_num :下一頁頁碼數
query :返回 創建這個Pagination對象的查詢對象
total :查詢返回的記錄總數
iter_pages(left_edge=2, left_current=2, right_current=5, right_edge=2)
在模版中使用
{% macro render_pagination(pagination, endpoint) %} <div class=pagination> {%- for page in pagination.iter_pages() %} {% if page %} {% if page != pagination.page %} <a href="{{ url_for(endpoint, page=page) }}">{{ page }}</a> {% else %} <strong>{{ page }}</strong> {% endif %} {% else %} <span class=ellipsis>…</span> {% endif %} {%- endfor %} </div> {% endmacro %}
七.事件監聽
Flask-SQLALchemy不但提供了方便的數據庫操作,還提供了事件的監聽,如下
from sqlalchemy import event def my_append_listener(target, value, initiator): print "received append event for target: %s" % target event.listen(MyClass.collection, 'append', my_append_listener)
Listeners have the option to return a possibly modified version of the value, when the retval=Trueflag is passed to listen():
def validate_phone(target, value, oldvalue, initiator): "Strip non-numeric characters from a phone number" return re.sub(r'(?![0-9])', '', value) # setup listener on UserContact.phone attribute, instructing # it to use the return value listen(UserContact.phone, 'set', validate_phone, retval=True)
A validation function like the above can also raise an exception such as ValueError to halt the operation.
Several modifiers are available to the listen() function.
Parameters: |
|
---|
- append ( target, value, initiator )
-
Receive a collection append event.
Parameters: - target – the object instance receiving the event. If the listener is registered with raw=True, this will be the InstanceState object.
- value – the value being appended. If this listener is registered withretval=True, the listener function must return this value, or a new value which replaces it.
- initiator – the attribute implementation object which initiated this event.
Returns: if the event was registered with retval=True, the given value, or a new effective value, should be returned.
- remove ( target, value, initiator )
-
Receive a collection remove event.
Parameters: - target – the object instance receiving the event. If the listener is registered with raw=True, this will be the InstanceState object.
- value – the value being removed.
- initiator – the attribute implementation object which initiated this event.
Returns: No return value is defined for this event.
- set ( target, value, oldvalue, initiator )
-
Receive a scalar set event.
Parameters: - target – the object instance receiving the event. If the listener is registered with raw=True, this will be the InstanceState object.
- value – the value being set. If this listener is registered with retval=True, the listener function must return this value, or a new value which replaces it.
- oldvalue – the previous value being replaced. This may also be the symbol NEVER_SET or NO_VALUE. If the listener is registered withactive_history=True, the previous value of the attribute will be loaded from the database if the existing value is currently unloaded or expired.
- initiator – the attribute implementation object which initiated this event.
Returns: if the event was registered with retval=True, the given value, or a new effective value, should be returned.