Flask學習記錄之Flask-SQLAlchemy

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:[email protected]: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:
  • active_history=False – When True, indicates that the “set” event would like to receive the “old” value being replaced unconditionally, even if this requires firing off database loads. Note that active_history can also be set directly viacolumn_property() and relationship().
  • propagate=False – When True, the listener function will be established not just for the class attribute given, but for attributes of the same name on all current subclasses of that class, as well as all future subclasses of that class, using an additional listener that listens for instrumentation events.
  • raw=False – When True, the “target” argument to the event will be theInstanceState management object, rather than the mapped instance itself.
  • retval=False – when True, the user-defined event listening must return the “value” argument from the function. This gives the listening function the opportunity to change the value that is ultimately used for a “set” or “append” event.
append(targetvalueinitiator)

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(targetvalueinitiator)

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(targetvalueoldvalueinitiator)

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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章