FlaskSQLAlchemy框架使用學習筆記
- SQLAlchemy是一個關係型數據庫框架,它提供了高層的 ORM 和底層的原生數據庫的操作。flask-sqlalchemy 是一個簡化了 SQLAlchemy 操作的flask擴展。
- SQLALchemy 實際上是對數據庫的抽象,讓開發者不用直接和 SQL 語句打交道,而是通過 Python 對象來操作數據庫,在捨棄一些性能開銷的同時,換來的是開發效率的較大提升
安裝
- 安裝 flask-sqlalchemy
pip install flask-sqlalchemy
- 如果連接的是 mysql 數據庫,需要安裝 mysqldb
pip install flask-mysqldb
創建完flask項目後,從flask_sqlalchemy中導入SQLAlchemy並實例化,代碼如下
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
數據庫連接設置
- 在 Flask-SQLAlchemy 中,數據庫使用URL指定,而且程序使用的數據庫必須保存到Flask配置對象的 SQLALCHEMY_DATABASE_URI 鍵中
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/monkey'
- 其他設置:
# 是否追蹤修改,一般設置爲False,因爲浪費資源,並且後期版本中將取消此設置
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查詢時會打印顯示原始SQL語句
app.config['SQLALCHEMY_ECHO'] = True
- 配置完成需要去 MySQL 中創建項目所使用的數據庫
$ mysql -uroot -p
$ 輸入密碼
$ create database moneky charset utf8;
數據庫連接和sqlalchemy連接數據庫代碼一樣,定義好數據庫連接後,我們就可以定義模型了(注意:模型繼承的類是db.Model,直接從db導入即可),代碼如下:
class User(db.Model):
__tablename__ = "user"
id = db.db.Column(db.Integer , primary_key=True , autoincrement=True)
name = db.db.Column(db.String(50) , nullable=False)
常用的SQLAlchemy字段類型
類型名 | python中類型 | 說明 |
---|---|---|
Integer | int | 普通整數,一般是32位 |
SmallInteger | int | 取值範圍小的整數,一般是16位 |
BigInteger | int或long | 不限制精度的整數 |
Float | float | 浮點數 |
Numeric | decimal.Decimal | 普通整數,一般是32位 |
String | str | 變長字符串 |
Text | str | 變長字符串,對較長或不限長度的字符串做了優化 |
Unicode | unicode | 變長Unicode字符串 |
UnicodeText | unicode | 變長Unicode字符串,對較長或不限長度的字符串做了優化 |
Boolean | bool | 布爾值 |
Date | datetime.date | 時間 |
Time | datetime.datetime | 日期和時間 |
LargeBinary | str | 二進制文件 |
常用的SQLAlchemy列選項
選項名 | 說明 |
---|---|
primary_key | 如果爲True,代表表的主鍵 |
unique | 如果爲True,代表這列不允許出現重複的值 |
index | 如果爲True,爲這列創建索引,提高查詢效率 |
nullable | 如果爲True,允許有空值,如果爲False,不允許有空值 |
default | 爲這列定義默認值 |
常用的SQLAlchemy參數
選項名 | 說明 |
---|---|
backref | 在關係的另一模型中添加反向引用 |
secondary | 指定多對多關係中關係表的名字 |
primaryjoin | 用在一對多或者多對一的關係中,默認情況連接條件就是主鍵與另一端的外鍵 |
order_by | order_by="desc(Address.email)"地址按照email排序 |
SQLAlchemy中的映射關係
有四種,分別是一對多,多對一,一對一,多對多
一對多(one to many):
因爲外鍵(ForeignKey)始終定義在多的一方.如果relationship定義在多的一方,那就是多對一,一對多與多對一的區別在於其關聯(relationship)的屬性在多的一方還是一的一方,如果relationship定義在一的一方那就是一對多.
這裏的例子中,一指的是Parent,一個parent有多個child:
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(Integer,primary_key = True)
children = relationship("Child",backref='parent')
class Child(db.Model):
__tablename__ = 'child'
id = db.Column(Integer,primary_key = True)
parent_id = db.Column(Integer,ForeignKey('parent.id'))
多對一(many to one):
這個例子中many是指parent了,意思是一個child可能有多個parent(父親和母親),這裏的外鍵(child_id)和relationship(child)都定義在多(parent)的一方:
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(Integer, primary_key=True)
child_id = db.Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref="parents")
class Child(db.Model):
__tablename__ = 'child'
id = db.Column(Integer, primary_key=True)
爲了建立雙向關係,可以在relationship()中設置backref,Child對象就有parents屬性.設置 cascade= ‘all’,可以級聯刪除:
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(Integer,primary_key = True)
children = relationship("Child",cascade='all',backref='parent')
def delete_parent():
session = Session()
parent = session.query(Parent).get(2)
session.delete(parent)
session.commit()
不過不設置cascade,刪除parent時,其關聯的chilren不會刪除,只會把chilren關聯的parent.id置爲空,設置cascade後就可以級聯刪除children
一對一(one to one):
一對一就是多對一和一對多的一個特例,只需在relationship加上一個參數uselist=False替換多的一端就是一對一:
從一對多轉換到一對一:
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(Integer,primary_key = True)
children = relationship("Child",cascade='all',backref='parent')
def delete_parent():
session = Session()
parent = session.query(Parent).get(2)
session.delete(parent)
session.commit()
從多對一轉換到一對一:
class Parent(db.Model):
__tablename__ = 'parent'
id = db.Column(Integer, primary_key=True)
child_id = db.Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref=backref("parent", uselist=False))
class Child(db.Model):
__tablename__ = 'child'
id = db.Column(Integer, primary_key=True)
多對多(many to many):
多對多關係需要一箇中間關聯表,通過參數secondary來指定,
from sqlalchemy import Table,Text
post_keywords = Table('post_keywords',Base.metadata,
db.Column('post_id',Integer,ForeignKey('posts.id')),
db.Column('keyword_id',Integer,ForeignKey('keywords.id'))
)
class BlogPost(db.Model):
__tablename__ = 'posts'
id = db.Column(Integer,primary_key=True)
body = db.Column(Text)
keywords = relationship('Keyword',secondary=post_keywords,backref='posts')
class Keyword(db.Model):
__tablename__ = 'keywords'
id = db.Column(Integer,primary_key = True)
keyword = db.Column(String(50),nullable=False,unique=True)
定義模型類 & 增刪改
創建表
db.create_all()
刪除表
db.drop_all()
插入一條數據
user = User(name='monkey')
db.session.add(user)
db.session.commit()
數據查詢
常用的SQLAlchemy查詢過濾器
過濾器 | 說明 |
---|---|
filter() | 把過濾器添加到原查詢上,返回一個新查詢 |
filter_by() | 把等值過濾器添加到原查詢上,返回一個新查詢 |
limit | 使用指定的值限定原查詢返回的結果 |
order_by() | 根據指定條件對原查詢結果進行排序,返回一個新查詢 |
常用的SQLAlchemy查詢執行器
方法 | 說明 |
---|---|
all() | 以列表形式返回查詢的所有結果 |
first() | 返回查詢的第一個結果,如果未查到,返回None |
first_or_404() | 返回查詢的第一個結果,如果未查到,返回404 |
get() | 返回指定主鍵對應的行,如不存在,返回None |
get_or_404() | 返回指定主鍵對應的行,如不存在,返回404 |
count() | 返回查詢結果的數量 |
paginate() | 返回一個Paginate對象,它包含指定範圍內的結果 |