flask框架--数据库ORM框架flask-sqlalchemy
1、使用sqlalchemy的配置
2、创建模型类
3、用代码预插数据
4、常用的SQLAlchemy查询执行器
5、常用的SQLAlchemy查询过滤器
6、数据的修改和删除
7、关联查询
8、图书案例
1、使用sqlalchemy的配置 <-返回目录
SQLALchemy实际上是对数据库的抽象,让开发者不用直接和SQL打交道,而是通过python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的提升。SQLALchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLALchemy操作的扩展。
安装
pip install flask-sqlalchemy
pip install flask-mysqldb -- 提供mysql驱动
sqlalchemy 的配置
# coding:utf-8 from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # sqlalchemy 的配置 app.config["SECRET_KEY"] = "TEST_SECRET_KEY" app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:123456@127.0.0.1:3306/db1" # 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True # 查询时显示原始SQL语句 app.config["SQLALCHEMY_ECHO"] = True db = SQLAlchemy(app)
2、创建模型类 <-返回目录
创建模型类时,常用的列选项
选项名 说明
primary_key 如果为True,代表表的主键
unique 如果为True,代表该列不允许出现重复的值
index 如果为True,为这列创建索引
nullable 如果为True,运行有空值,如果为False,不允许有空值
default 为该列定义默认值
创建模型类Role和User
# coding:utf-8 from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # sqlalchemy 的配置 app.config["SECRET_KEY"] = "TEST_SECRET_KEY" app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:123456@127.0.0.1:3306/db1" # 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True # 查询时显示原始SQL语句 app.config["SQLALCHEMY_ECHO"] = True db = SQLAlchemy(app) # 创建模型类 class Role(db.Model): __tablename__ = "tb_role" id = db.Column(db.Integer, primary_key = True) # 整形的主键,默认设置为自增主键 name = db.Column(db.String(32), unique =True) users = db.relationship("User", backref = "role") class User(db.Model): __tablename__ = "tb_user" id = db.Column(db.Integer, primary_key = True) # 整形的主键,默认设置为自增主键 name = db.Column(db.String(64), unique = True) email = db.Column(db.String(100), unique = True) password = db.Column(db.String(100)) role_id = db.Column(db.Integer, db.ForeignKey("tb_role.id")) # 外键,存储tb_role表的id if __name__ == "__main__": # app.run(host="0.0.0.0", port=8080, debug=True) db.drop_all() # 清除数据库里的所有数据 db.create_all() # 创建所有表
db.create_all() 自动创建表,发送的SQL为:
CREATE TABLE tb_role ( id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR(32), PRIMARY KEY (id), UNIQUE (name) ) CREATE TABLE user ( id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR(64), email VARCHAR(100), password VARCHAR(100), role_id INTEGER, PRIMARY KEY (id), UNIQUE (name), UNIQUE (email), FOREIGN KEY(role_id) REFERENCES tb_role (id) )
3、用代码预插数据 <-返回目录
if __name__ == "__main__": db.drop_all() # 清除数据库里的所有数据 db.create_all() # 创建所有表 role1 = Role(name="admin") role2 = Role(name="staff") db.session.add(role1) db.session.add(role2) db.session.commit() user1 = User(name='wang', email='wang@163.com', password='123456', role_id=role1.id) user2 = User(name='zhang', email='zhang@163.com', password='464643', role_id=role2.id) user3 = User(name='chen', email='chen@163.com', password='497594', role_id=role2.id) user4 = User(name='zhou', email='zhou@163.com', password='402994', role_id=role1.id) db.session.add_all([user1, user2, user3, user4]) db.session.commit()
4、常用的SQLAlchemy查询执行器 <-返回目录
方法 说明
all() 以列表形式返回查询的所有结果
first() 返回查询的第一个结果,如果未查到,返回None
first_or_404() 返回查询的第一个结果,如果未查到,返回404
get() 返回指定主键对应的行,如果不存在,返回None
get_or_404() 返回指定主键对应的行,如果不存在,返回404
count() 返回查询结果的数量
paginate() 返回一个Pagenate对象,它包含指定范围内的结果
使用示例
def query(): # 查询所有 # li = Role.query.all() # print(type(li[0])) # print(li[0].name) # 查询first # Role.query.first() # print(type(r)) # print(r.name) # 根据主键查询 # r = Role.query.get(2) # print(type(r)) # print(r.name) # 查询count # count = Role.query.count() # print(count) # 另外一种用法 # li = db.session.query(Role).all() # print(type(li[0])) # print(li[0].name) r = db.session.query(Role).get(2) print(type(r)) print(r.name) if __name__ == "__main__": query()
5、常用的SQLAlchemy查询过滤器 <-返回目录
过滤器 说明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit() 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询
示例
def query(): # li = User.query.filter_by(name="wang").all() # print(type(li[0])) # print(li[0].email) # li = User.query.filter_by(name="zhang", role_id=2).all() # print(type(li[0])) # print(li[0].email) li = User.query.filter(User.name=="zhang", User.role_id==2).all() print(type(li[0])) print(li[0].email) if __name__ == "__main__": query()
or 条件的拼接 from sqlalchemy import or_
li = User.query.filter(or_(User.name=="wang", User.email.endswith("163.com"))).all() print(li)
排序
li = User.query.order_by(User.id.desc()).all() print(li)
分组 from sqlalchemy import func
li = db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id).all() print(li)
6、数据的修改和删除 <-返回目录
修改
def update(): # user = User.query.get(1) # user.name = "abc" # db.session.add(user) # db.session.commit() User.query.filter_by(name="abc").update({"name": "wang", "email": "abc@126.com"}) db.session.commit() if __name__ == "__main__": update()
删除
user = User.query.get(1)
db.session.delete(user)
db.session.commit()
7、关联查询 <-返回目录
# role = Role.query.get(1) # print(role.users) user = User.query.get(1) print(user.role)
因为模型类Role中配置了 users = db.relationship("User", backref="role"),所以根据主键查询User时,关联查询对应的Role。
SQL打印信息:
2022-02-15 16:50:53,059 INFO sqlalchemy.engine.Engine SELECT tb_user.id AS tb_user_id, tb_user.name AS tb_user_name, tb_user.email AS tb_user_email, tb_user.password AS tb_user_password, tb_user.role_id AS tb_user_role_id FROM tb_user WHERE tb_user.id = %s 2022-02-15 16:50:53,059 INFO sqlalchemy.engine.Engine [generated in 0.00023s] (1,) 2022-02-15 16:50:53,062 INFO sqlalchemy.engine.Engine SELECT tb_role.id AS tb_role_id, tb_role.name AS tb_role_name FROM tb_role WHERE tb_role.id = %s 2022-02-15 16:50:53,063 INFO sqlalchemy.engine.Engine [generated in 0.00050s] (1,) <Role 1>
8、图书案例 <-返回目录
# coding:utf-8 from flask import Flask, render_template, redirect, url_for from flask_sqlalchemy import SQLAlchemy from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired app = Flask(__name__) app.config["SECRET_KEY"] = "TEST_SECRET_KEY" # sqlalchemy 的配置 app.config["SECRET_KEY"] = "TEST_SECRET_KEY" app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:123456@127.0.0.1:3306/db1" # 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True # 查询时显示原始SQL语句 app.config["SQLALCHEMY_ECHO"] = True db = SQLAlchemy(app) # 创建模型类 class Author(db.Model): __tablename__ = "tb_author" id = db.Column(db.Integer, primary_key = True) # 整形的主键,默认设置为自增主键 name = db.Column(db.String(32), unique =True) books = db.relationship("Book", backref = "author") class Book(db.Model): __tablename__ = "tb_book" id = db.Column(db.Integer, primary_key = True) # 整形的主键,默认设置为自增主键 name = db.Column(db.String(64), unique = True) author_id = db.Column(db.Integer, db.ForeignKey("tb_author.id")) # 外键,存储tb_author表的id # 预制数据库数据 def pre_insert_data(): db.drop_all() db.create_all() auth1 = Author(name="罗贯中") auth2 = Author(name="施耐庵") auth3 = Author(name="吴承恩") auth4 = Author(name="曹雪芹") db.session.add_all([auth1, auth2, auth3, auth4]) db.session.commit() book1 = Book(name="三国演义", author_id=auth1.id) book2 = Book(name="水浒传", author_id=auth2.id) book3 = Book(name="西游记", author_id=auth3.id) book4 = Book(name="红楼梦", author_id=auth4.id) book5 = Book(name="三国演义2", author_id=auth1.id) db.session.add_all([book1, book2, book3, book4, book5]) db.session.commit() # 定义表单模型类 class AuthorBookForm(FlaskForm): """自定义的表单模型类""" # DataRequired 验证器:保证数据必填,并且不能为空 author_name = StringField(label="作者", validators=[DataRequired("作者不能为空")]) book_name = StringField(label="书籍", validators=[DataRequired("书籍不能为空")]) submit = SubmitField(label="提交") @app.route("/index", methods = ["get", "post"]) def index(): # 创建表单对象。如果时post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中 authorBookForm = AuthorBookForm() author_li = Author.query.all() return render_template("author_book.html", authors=author_li, authorBookForm=authorBookForm) @app.route("/add", methods = ["post"]) def add_book(): # 创建表单对象。如果时post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中 authorBookForm = AuthorBookForm() # 判断form中的数据是否合理。如果form中的数据完全满足所有的验证器,则返回真,否则返回假 if authorBookForm.validate_on_submit(): # 验证通过 author_name = authorBookForm.author_name.data book_name = authorBookForm.book_name.data print("验证通过, author_name: {0}, book_name: {1}".format(author_name, book_name)) # 根据作者名查询, 保存书籍 author = Author.query.filter_by(name=author_name).first() if author == None: auth = Author(name=author_name) db.session.add(auth) db.session.commit() book = Book(name=book_name, author_id = auth.id) db.session.add(book) db.session.commit() else: book = Book(name=book_name, author_id = author.id) db.session.add(book) db.session.commit() return redirect(url_for("index")) @app.route("/delete_book/<book_id>") def delete_book(book_id): print("delete_book book_id: {0}".format(book_id)) if book_id == None: return redirect(url_for("index")) book = Book.query.get(book_id) if book == None: print("查询不到书籍记录, book_id: {0}".format(book_id)) else: db.session.delete(book) db.session.commit() return redirect(url_for("index")) @app.route("/delete_author/<author_id>") def delete_author(author_id): print("delete_authro author_id: {0}".format(author_id)) if author_id == None: return redirect(url_for("index")) author = Author.query.get(author_id) if author == None: print("查询不到指定作者, author_id: {0}".format(author_id)) else: # 先删除作者下面所有书籍,然后删除作者 for book in author.books: db.session.delete(book) db.session.delete(author) db.session.commit() return redirect(url_for("index")) if __name__ == "__main__": # pre_insert_data() app.run(host="0.0.0.0", port=8080, debug=True)
author_book.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <form method="post" action="/add"> {{ authorBookForm.csrf_token }} <!-- 作者 --> {{ authorBookForm.author_name.label }}: {{ authorBookForm.author_name }} <!-- 错误提示信息 --> {% for msg in authorBookForm.author_name.errors %} {{ msg }} {% endfor %} <br/> <!-- 书籍 --> {{ authorBookForm.book_name.label }}: {{ authorBookForm.book_name }} {% for msg in authorBookForm.book_name.errors %} {{ msg }} {% endfor %} <br/> <!-- 提交 --> {{ authorBookForm.submit.label }}: {{ authorBookForm.submit }} </form> <hr/> <ul> {% for author in authors %} <li> 作者:{{ author.name}} <a href="/delete_author/{{author.id}}">删除</a> <ul> {% for book in author.books %} <li>书籍:{{ book.name }} <a href="/delete_book/{{book.id}}">删除</a></li> {% endfor %} </ul> </li> {% endfor %} </ul> </body> </html>
其他参考:
posted on 2022-02-15 16:58 wenbin_ouyang 阅读(767) 评论(0) 编辑 收藏 举报