flask-sqlachemy
1 ORM
flask-sqlachemy让flask框架可以继承sqlachemy框架
sqlachemy是python中最著名的ORM框架
ORM:对象关系映射(Object-Relation Mapping)可以允许开发者使用原生代码的方式来操作数据库
优点:开发者不用写SQL语句,而且也不需要学习其他数据库的SQL语法
缺点:存在一定的性能缺失
2 .创建连接
需要安装
pip install flask_sqlalchemy
pip install flask_mysqldb
py代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://数据库用户名:密码@127.0.0.1:3306/test23'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 创建数据连接
db = SQLAlchemy(app)
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
app.run(debug=True)
3,基础操作
py代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql:root:mysql@127.0.0.1:3306/test23'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 创建数据连接
db = SQLAlchemy(app)
# 映射关系 类>表 属性>字段 对象>记录
class User(db.Model):
__tablename__ = 't_user' # 设置表名,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
@app.route('/')
def index():
# 删除所有继承db.Model的表
db.drop_all()
# 创建所有继承db.Model的表
db.create_all()
# 创建对象(模型)
user1 = User(name='zs')
# 将对象添加到会话(事物)中
db.session.add(user1)
# 提交会话(事物),必须提交,否则数据库不会变化
db.session.commit()
return 'index'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
4,增删改
py代码
# 增加对象
user2 = User(name='ls')
db.session.add(user2)
db.session.commit()
user3 = User(name='ls')
db.session.add(user3)
db.session.commit()
# 修改数据
user2.name = 'ww'
db.session.commit()
# 删除数据
db.session.delete(user2)
db.session.commit()
5,数据查询
py代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test21'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# # 设置控制台是否打印底层语句
# app.config['SQLALCHEMY_ECHO'] = True
# 创建数据连接
db = SQLAlchemy(app)
# ⾃定义类 继承db.Model 对应 表
class User(db.Model):
__tablename__ = "users" # 表名 默认使⽤类名的⼩写
# 定义类属性 记录字段
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
email = db.Column(db.String(64))
age = db.Column(db.Integer)
def __repr__(self): # ⾃定义 交互模式 & print() 的对象打印
return "(%s, %s, %s, %s)" % (self.id, self.name, self.email, self.age)
# def select():
# # 查询所有⽤户数据
# User.query.all()
#
# # 查询有多少个⽤户
# User.query.count()
#
# # 查询第1个⽤户
# User.query.first()
#
# # 查询id为3的⽤户[3种⽅式]
# User.query.get(3) # 根据主键查询
# User.query.filter_by(id=3).all() # 以关键字实参形式进行匹配字段
# User.query.filter(User.id == 3).all() # 以恒等式形式匹配字段
#
# # 查询名字结尾字符为g的所有⽤户[开始 /
# User.query.filter(User.name.endswith('g')).all()
#
# # 查询名字包含‘n'的所有项目
# User.query.filter(User.name.contains('n').all()
# User.query.filter(User.name.like('w%n%g').all() # 模糊查询
#
# # 查询名字和邮箱都以li开头的所有⽤户[2种⽅式]
# User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()
#
# from sqlalchemy import and_
#
# User.query.filter(and_(User.name.startswith('li'),User.email.startswith('li'))).all()
#
# # 查询age是25 或者 `email`以`itheima.com`结尾的所有⽤户
# from sqlalchemy import or_
# User.query.filter(or_(User.age==25,User.email.endswith('itheima.com'))).all()
#
# # 查询名字不等于wang的所有⽤户[2种⽅式]
# from sqlalchemy import not_
# User.query.filter(not_(User.name=='wang')).all()
#
# User.query.filter(User.name != 'wang').all()
#
# # 查询id为[1, 3, 5, 7, 9]的⽤户
# User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()
#
# # 所有⽤户先按年龄从⼩到⼤, 再按id从⼤到⼩排序, 取前5个
# User.query.order_by(User.age,User.id.desc()).limit(5).all()
#
# # 分⻚查询, 每⻚3个, 查询第2⻚的数据
# pn = User.query.paginate(2,3)
# pn.pages
# pn.page
# pn.items
if __name__ == '__main__':
# 删除所有表
db.drop_all()
# 创建所有表
db.create_all()
# 添加测试数据
user1 = User(name='wang', email='wang@163.com', age=20)
user2 = User(name='zhang', email='zhang@189.com', age=33)
user3 = User(name='chen', email='chen@126.com', age=23)
user4 = User(name='zhou', email='zhou@163.com', age=29)
user5 = User(name='tang', email='tang@itheima.com', age=25)
user6 = User(name='wu', email='wu@gmail.com', age=25)
user7 = User(name='qian', email='qian@gmail.com', age=23)
user8 = User(name='liu', email='liu@itheima.com', age=30)
user9 = User(name='li', email='li@163.com', age=28)
user10 = User(name='sun', email='sun@163.com', age=26)
# ⼀次添加多条数据
db.session.add_all([user1, user2, user3, user4, user5, user6, user7, user8, user9, user10])
db.session.commit()
# select()
app.run(debug=True)
6一对多
- 定义外键
use_id = db.Column(db.Integer,db.ForeignKey('t_user.id')) # 定义外健,必须在多的一方
- 定义关系属性
addreses = db.relationship('Addres') # 定义关系属性
- 1 反向关系属性
addreses = db.relationship('Addres',backref='user_info')
- 添加到关系属性列表进行关联
user1 = User(name='zs')
adr1 = Addres(name='中关村1号')
adr2 = Addres(name='华强北5号')
user1.addreses.append(adr1)
user1.addreses.append(adr2)
- 使用关系属性查询
User.query.filter_by(name='zs').first()
adrs = user1.addreses
for adr in adrs:
print(adr.name)
6.1 实例
py代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test23'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置控制台是否打印底层语句
# app.config['SQLALCHEMY_ECHO'] = True
# 创建数据连接
db = SQLAlchemy(app)
# 映射关系 类>表 属性>字段 对象>记录
class User(db.Model):
__tablename__ = 't_user' # 设置表面,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
addreses = db.relationship('Addres') # 定义关系属性
class Addres(db.Model):
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
use_id = db.Column(db.Integer,db.ForeignKey('t_user.id')) # 定义外健,必须在多的一方
@app.route('/')
def index():
# 删除所以继承db.Model的表
db.drop_all()
# 创建所以继承db.Model的表
db.create_all()
# 创建对象(模型)
user1 = User(name='zs')
adr1 = Addres(name='中关村1号')
adr2 = Addres(name='华强北5号')
user1.addreses.append(adr1)
user1.addreses.append(adr2)
db.session.add_all([adr1,adr2,user1]) # 使用的是add_all([])
db.session.commit()
User.query.filter_by(name='zs').first()
adrs = user1.addreses
for adr in adrs:
print(adr.name)
return 'index'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
7综合案例>图书管理
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
<label>作者:</label>
<input type="text" name="author" placeholder="请输入作者名"><br/>
<label>书名:</label>
<input type="text" name="book" placeholder="请输入书名"><br/>
<input type="submit" value="添加">
</form>
<ul>
{% for author in authors %}
<li>{{ author.name }}<a href="{{ url_for('delete_author',author_id=author.id) }}">删除</a></li>
{% for book in author.books %}
<ul>
<li>{{ book.name }}<a href="{{ url_for('delete_book',book_id=book.id) }}">删除</a></li>
</ul>
{% endfor %}
{% endfor %}
</ul>
{% for message in get_flashed_messages() %}
<script>alert('{{ message }}')</script>
{% endfor %}
</body>
</html>
py代码
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/book23'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置控制台是否打印底层语句
# app.config['SQLALCHEMY_ECHO'] = True
# 创建数据连接
db = SQLAlchemy(app)
# flash使用的是session保存内容,所以一定要设在密钥
app.secret_key = 'test'
# 映射关系 类>表 属性>字段 对象>记录
class Author(db.Model):
__tablename__ = 't_author' # 设置表面,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
books = db.relationship('Book', backref='author_info')
class Book(db.Model):
__tablename__ = 't_book' # 设置表面,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
author_id = db.Column(db.Integer, db.ForeignKey('t_author.id'))
@app.route('/', methods=['GET', 'POST'])
def index():
method = request.method
if method == 'GET':
authors = Author.query.all()
return render_template('book.html', authors=authors)
author_name = request.form.get('author')
book_name = request.form.get('book')
if not all([author_name, book_name]):
flash('参数错误!')
return redirect(url_for('index'))
# print(author_name)
# print(Author.query.all())
# for i in Author.query.all():
# print(i.name)
try:
author = Author.query.filter_by(name=author_name).first()
# print(author)
except Exception as e:
flash('查询错误')
return redirect(url_for('index'))
try:
if author:
book = Book(name=book_name)
author.books.append(book)
db.session.add(book)
db.session.commit()
else:
author = Author(name=author_name)
book = Book(name=book_name)
author.books.append(book)
db.session.add_all([book, author])
db.session.commit()
except Exception as e:
flash('操作失败')
db.session.rollback()
return redirect(url_for('index'))
@app.route('/delete_book/<int:book_id>')
def delete_book(book_id):
try:
book = Book.query.get(book_id)
db.session.delete(book)
db.session.commit()
except Exception as e:
flash('删除书籍失败')
db.session.rollback()
return redirect(url_for('index'))
@app.route('/delete_author/<int:author_id>')
def delete_author(author_id):
try:
author = Author.query.get(author_id)
except Exception as e:
flash('查询失败')
return redirect(url_for('index'))
try:
for book in author.books:
db.session.delete(book)
db.session.delete(author)
db.session.commit()
except Exception as e:
flash('删除作者失败')
db.session.rollback()
return redirect(url_for('index'))
if __name__ == '__main__':
# 删除所以继承db.Model的表
db.drop_all()
# 创建所以继承db.Model的表
db.create_all()
# ⽣成数据
au1 = Author(name="老王")
au2 = Author(name="老尹")
au3 = Author(name="老刘")
# 把数据提交给⽤户会话
db.session.add_all([au1, au2, au3])
# 提交会话
db.session.commit()
bk1 = Book(name='⽼王回忆录', author_id=au1.id)
bk2 = Book(name='我读书少,你别骗我', author_id=au1.id)
bk3 = Book(name='如何才能让⾃⼰更骚', author_id=au2.id)
bk4 = Book(name='怎样征服美丽少⼥', author_id=au3.id)
bk5 = Book(name='如何征服英俊少男', author_id=au3.id)
# 把数据提交给⽤户会话
db.session.add_all([bk1, bk2, bk3, bk4, bk5])
# 提交会话
db.session.commit()
app.run(host='0.0.0.0', port=8080, debug=True)
8多对多
py代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test23'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 创建数据连接
db = SQLAlchemy(app)
# 映射关系 类>表 属性>字段 对象>记录
class Student(db.Model):
__tablename__ = 't_student' # 设置表面,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
courses = db.relationship('Course',backref='students',secondary='t_student_course')
class Course(db.Model):
__tablename__ = 't_course' # 设置表面,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False)
class Student_course(db.Model):
__tablename__ = 't_student_course' # 设置表面,表名默认为类名小写
stu_id = db.Column(db.Integer, db.ForeignKey('t_student.id'),primary_key=True)
cour_id = db.Column(db.Integer, db.ForeignKey('t_course.id'), primary_key=True)
if __name__ == '__main__':
# 删除所以继承db.Model的表
db.drop_all()
# 创建所以继承db.Model的表
db.create_all()
stu1 = Student(name='zs')
stu2 = Student(name='ls')
cour1 = Course(name='c')
cour2 = Course(name='python')
cour3 = Course(name='java')
stu1.courses.append(cour1)
stu1.courses.append(cour2)
stu2.courses.append(cour2)
stu2.courses.append(cour3)
db.session.add_all([stu1,stu2,cour1,cour2,cour3])
db.session.commit()
cours = stu1.courses
for cour in cours:
print(cour.name)
app.run(host='0.0.0.0', port=8080, debug=True)
9数据库迁移
在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库。最直接的方式就是删除旧表,但这样会丢失数据。
更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中。
在Flask中可以使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成。
为了导出数据库迁移命令,Flask-Migrate提供了一个MigrateCommand类,可以附加到flask-script的manager对象上。
首先要在虚拟环境中安装Flask-Migrate。
pip install flask-migrate
代码文件内容:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Manager
app = Flask(__name__)
# 设置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test20'
# 设置是否跟踪数据库变化,开启非常影响性能,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 创建数据连接
db = SQLAlchemy(app)
mgr = Manager(app)
# 初始化迁移器
Migrate(app,db)
# 管理器生成迁移命令
mgr.add_command('mc',MigrateCommand)
# 映射关系 类>表 属性>字段 对象>记录
class User(db.Model):
__tablename__ = 't_user' # 设置表面,表名默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 标识为主键
name = db.Column(db.String(40), unique=True, nullable=False) # 标识唯一且不能为空值
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
# # 删除所以继承db.Model的表
# db.drop_all()
#
# # 创建所以继承db.Model的表
# db.create_all()
# app.run(host='0.0.0.0', port=8080, debug=True)
mgr.run()
1.创建迁移仓库
这个命令会创建migrations文件夹,所有迁移文件都放在里面.(在终端中输入以下代码)
python database.py mc init
2.生成迁移版本
python xx.py mc migrate -m "注释"
3.执行升级操作
python xx.py mc upgrade
实际操作顺序:
1.python 文件 mc init
2.python 文件 mc migrate -m"版本名(注释)"
3.python 文件 mc upgrade 然后观察表结构
4.根据需求修改模型
5.python 文件 mc migrate -m"新版本名(注释)"
6.python 文件 mc upgrade 然后观察表结构
7.若返回版本,则利用 python 文件 mc history查看版本号
8.python 文件 mc downgrade(upgrade) 版本号