安装
pip install flask-sqlalchemy
初始化
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
db = SQLAlchemy(app)
连接数据库
示例:
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:123.com@localhost/test01"
定义数据库模型
# 模型要继承于db.Model基类
class User(db.Model):
# 指定表名,不设置默认 User -> user
__tablename__ = "users"
# 字段由db.Column的实例表示,类型通过构造方法的第一个参数传入,第二个参数实例化字段时的一些参数字段
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True)
def __repr__(self):
"""非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
return '' % self.name
第一个数据类型
第二个参数字段说明
创建数据库和表
# 丢弃表
db.drop_all()
# 创建表
db.create_all()
Create
示例是在python shell中进行
# 导入模型类和数据库
from test import User,db
# 实例化模型类
user01 = User(username="lilei")
user02 = User(username="zhangsan")
user03 = User(username="wangwu")
# 添加记录到数据库会话中
db.session.add(user01)
db.session.add(user02)
db.session.add(user03)
# 提交保存
db.session.commit()
Read
查询规则:
<模型类>.query.<过滤方法>.<查询方法>
示例:
# 查询
# 查询user表中所有记录
User.query.all()
# 返回查询的第一条记录,如果没有返回None
User.query.first()
# 返回指定的主键ID的值
User.query.get(id)
# 查看表中有多少条数据
User.query.count()
# 过滤
# 查找名字为lisi的记录
User.query.filter_by(username='lisi').first()
# like用法
User.query.filter(User.username.like('%is%')).first()
# in 用法
User.query.filter(User.username.in_(['lisi','zhangsan'])).all()
# notin 用法
User.query.filter(~User.username.in_(['lisi','zhangsan'])).all()
# and 和 or 用法
# 多条件可以直接用逗号拼接
User.query.filter(User.username=='lisi',User.id==3).all()
# 引入and和or
from sqlalchemy import and_, or_
# 使用 and
User.query.filter(and_(User.username=='lisi',User.id==3)).all()
# 使用 or
User.query.filter(or_(User.username=='lisi',User.id==2)).all()
更多查询和过滤方法:
Update
示例:
# 查询出要修改的对象
user01 = User.query.get(2)
# 修改值
user01.username="sunliu"
# 提交更新
db.session.commit()
Delete
# 查询出要删除的对象
user01 = User.query.get(2)
# 删除操作
db.session.delete(user01)
# 提交修改
db.session.commit()
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import pymysql
from sqlalchemy import and_, or_
app = Flask(__name__)
# 连接数据库
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:123.com@localhost/test01"
# 配置语句追踪
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
pymysql.install_as_MySQLdb()
db = SQLAlchemy(app)
# class Role(db.Model):
# __tablename__ = "roles"
# id = db.Column(db.Integer, primary_key=True)
# name = db.Column(db.String(64), unique=True)
#
# def __repr__(self):
# """非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
# return '' % self.name
#
#
# class User(db.Model):
# __tablename__ = 'users'
# id = db.Column(db.Integer, primary_key=True)
# username = db.Column(db.String(64), unique=True, index=True)
#
# def __repr__(self):
# """非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
# return '' % self.username
# 单向关系
# class Author(db.Model):
# __tablename__ = "author"
# id = db.Column(db.Integer, primary_key=True)
# name = db.Column(db.String(64), unique=True)
# phone = db.Column(db.String(20))
# # 定义关系属性,relationship的参数为另一侧的模型名称
# # 当被调用时,会找到关联的另一侧表的外键,然后反向查询article表中所有author_id为当前记录的,并返回此记录的列表
# article = db.relationship("Article")
#
# def __repr__(self):
# """非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
# return '' % self.name
#
#
# class Article(db.Model):
# __tablename__ = "article"
# id = db.Column(db.Integer, primary_key=True)
# title = db.Column(db.String(64), unique=True)
# body = db.Column(db.Text)
# author_id = db.Column(db.Integer, db.ForeignKey("author.id"))
#
# def __repr__(self):
# """非必须, 用于在调试或测试时, 返回一个具有可读性的字符串表示模型."""
# return '' % self.title
#
# # 双向关系
# class Writer(db.Model):
# id = db.Column(db.Integer, primary_key=True)
# name = db.Column(db.String(64), unique=True)
# # 定义关系属性,relationship的参数为另一侧的模型名称
# # 当被调用时,会找到关联的另一侧表的外键,然后反向查询article表中所有author_id为当前记录的,并返回此记录的列表
# books = db.relationship("Book", back_populates='writer')
#
#
# class Book(db.Model):
# id = db.Column(db.Integer, primary_key=True)
# title = db.Column(db.String(64), unique=True)
# writer_id = db.Column(db.Integer, db.ForeignKey('writer.id'))
# # 定义关系属性,relationship的参数为另一侧的模型名称
# # 当被调用时,会找到关联的另一侧表的外键,并返回此记录的列表
# writer = db.relationship("Writer", back_populates='books')
# 一对一
class Country(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
# 定义关系属性,relationship的参数为另一侧的模型名称
# 创建另一侧的关系属性,将集合属性userlist设为False
capital = db.relationship("Capital", userlist=False)
class Capital(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
country_id = db.Column(db.Integer, db.ForeignKey('country.id'))
# 定义关系属性,relationship的参数为另一侧的模型名称
# 当被调用时,会找到关联的另一侧表的外键,并返回此记录的列表
writer = db.relationship("Country")
if __name__ == '__main__':
# 创建删除表
# db.drop_all()
# db.create_all()
# 单向关系 示例
# foo = Author(name="foo")
# spam = Article(title='span')
# ham = Article(title='ham')
# db.session.add(foo)
# db.session.add(spam)
# db.session.add(ham)
# 配置属性关系
# 指定author_id
# spam = Article.query.get(1)
# spam.author_id = 1
# 通过关系属性操作,推荐使用
# ham = Article.query.get(2)
# foo = Author.query.get(1)
# 如果要解除关系属性可以使用remove
# foo.article.append(ham)
# db.session.commit()
# print(foo.article)
# 双向关系示例
# 写入记录
# king = Writer(name='king')
# carrie = Book(title="carrie")
# it = Book(title="it")
# db.session.add(king)
# db.session.add(carrie)
# db.session.add(it)
# 查询出记录
# carrie = Book.query.get(1)
# it = Book.query.get(2)
# king = Writer.query.get(1)
# 建立关系
# carrie.writer = king
# it.writer = king
# 解除关系
# carrie.writer = None
# 展示结果
# print(king.books)
# # 提交更新
# db.session.commit()
问题一
启动时,报错:Error loading MySQLdb module: No module named 'MySQLdb'。
MySQLdb并不支持Python3.5,因此只能找别的类库代替。
使用pymysql代替MySQLdb,因为两者的用法完全一致,步骤:
1. PIP install pymysql
2. 执行成功后,打开__init__.py,添加如下:
import pymysql
pymysql.install_as_MySQLdb()
问题二
启动时,出现警告FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and 'flask-sqlalchemy建议设置SQLALCHEMY_TRACK_MODIFICATIONS,此配置决定是否追踪对象的修改,默认None,设置为False
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
终极版:
# 一对多关系
class Role(db.Model):
# ...
# db.relationship() 的第一个参数表明这个关系的另一端是哪个模型
# backref 参数向 User 模型中添加一个 role 属性,从而定义反向关系。这一属性可替代 role_id 访问 Role 模型,此时获取的是模型对象,而不是外键的值
users = db.relationship('User', backref='role')
class User(db.Model):
# ...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
选项名 | 说 明 |
backref | 在关系的另一个模型中添加反向引用 |
primaryjoin | 明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定 |
lazy | 指定如何加载相关记录。可选值有 select (首次访问时按需加载)、immediate (源对象加载后就加载)、 joined (加载记录,但使用联结)、 subquery (立即加载,但使用子查询),noload (永不加载)和 dynamic (不加载记录,但提供加载记录的查询) |
uselist | 如果设为 Fales ,不使用列表,而使用标量值 |
order_by | 指定关系中记录的排序方式 |
secondary | 指定多对多关系中关系表的名字 |
secondaryjoin | SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件 |
# 多对多
# 建立关联表存储关系
tmp_tab = db.Table('tmp_tab',
db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
db.Column('class_id', db.Integer, db.ForeignKey('class.id')))
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
# 原始表添加关联表, 仍然使用relationshi定义关系,
classes = db.relationship('Class',
# 指定关联表
secondary=tmp_tab,
# 隐式定义引用关系
backref=db.backref('students', lazy='dynamic'),
lazy='dynamic')
#
class Class(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))