三、Flask模型基础 ORM

1. Flask模型Model

Flask默认并没有提供任何数据库操作的API

我们可以选择任何适合自己项目的数据库来使用Flask中可以自己的选择用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine) 原生SQL缺点

代码利用率低,条件复杂代码语句越长,有很多相似语句一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑直接写SQL容易忽视SQL问题

2. ORM

​ Flask通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite,Flask自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作F lask帮我们自动完成。只要会写Model就可以了, ​ Flask使用对象关系映射(object Relational Mapping,简称ORM)框架去操控数据库。 ​ ORM(object Relational Mapping)对象关系映射,是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。 ​ 将对对象的操作转换为原生SQL 优点

易用性,可以有效减少重复SQL性能损耗少设计灵活,可以轻松实现复杂查询移植性好

3. Flask的ORM

I. ORM

Flask使用Python自带的ORM: SQLAlchemy针对于flask的支持,安装插件flask- sqlalchemypip install flask-sqlalchemy

II. 连接SQLite

SQLite连接的URI:

DB_URI = sqlite:///sqlite3.db

III. 连接MySQL

USERNAME= 'root'

PASSWORD= 'admin123'

HOSTNAME = 'localhost'

PORT = '3306'

DATABASE = 'HelloFlask'

# 格式: mysql+pymysql://USERNAME@PASSWORDHOSTNANE:PORT/DATABASE

# 配置URL

DB_URI='mysql+pyaysql://{}:{}@{}:{}/{}'.format(

USERNAME,

PASSWORD,

HOSTNAME,

PORT,

DATABASE

)

IV. 在Flask中使用ORM

模型相关包安装 #安装flask-sqlalchemy (用 于ORM)

pip install flask-sqlalchemy

#安装flask-migrate (用于数据迁移)

pip install flask-migrate

#安装pymysql (MySQL驱动)

pip install pymysql

在App目录下新增exts.py用于插件管理 # exts.py 插件管理

# 1.导包

from flask_sqlalchemy import SQLAlchemy

from flask_migrate import Migrate

# 2.初始化

db = SQLAlchemy() # ORM

migrate = Migrate() # 数据迁移

# 3.和app对象绑定

def init_exts(app):

db.init_app(app=app)

migrate.init_app(app=app, db=db)

在models.py中构建模型 # model.py : 模型,数据库

from .exts import db

# 模型 => 数据库

# 类 => 表结构

# 类属性 => 表字段

# 一个类对象 => 表的一行数据

# 模型Model: 类

# 必须继承db.Model

class User(db.Model):

# 表名

__tablename__ = 'tb_user'

# 定义表字段

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(30), unique=True, index=True)

age = db.Column(db.Integer, default=1)

sex = db.Column(db.Boolean, default=True)

salary = db.Column(db.Float, default=100000.0, nullable=False)

salary2 = db.Column(db.Float, default=100000.0, nullable=False)

# db.Column : 表示字段

# db.Integer : 表示整数

# primary_key=True : 主键

# autoincrement=True :

# db.String(30) : varchar(30) 可变字符串

# unique=True : 唯一约束

# defalut=1 : 默认值为1

# nullable=False : 不允许为空

在App目录下的__init__.py,配置数据库相关参数,初始化数据库连接 # __init__.py : 初始化文件,创建Flask应用

from flask import Flask

from .views import blue

from .exts import init_exts

def create_app():

app = Flask(__name__)

# 注册蓝图

app.register_blueprint(blueprint=blue)

# 配置数据库,SQLite数据库连接不需要额外驱动,也不需要用户名和密码

db_uri = 'sqlite:///sqlite3.db'

app.config['SQLALCHEMY_DATABASE_URI'] = db_uri # 配置连接的数据库路径

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 禁止对象追踪修改

# 初始化插件

init_exts(app)

return app

数据迁移 数据迁移详细步骤:

1.安装好数据迁移的包flask-sqlalchemy和flask-migrate 2.在exts.py中初始化Migrate和sQLAlchemy 3.在models中定义好模型 4.在views.py中一定要导入models模块 from .models import *

5.配置好数据库(sqlite3或MysQL) 6.执行数据迁移命令:

6.1 先在cmd或Terminal进入项目目录(app.py所在目录)∶6.2 然后输入命令:

flask db init 创建迁移文件夹migrates,只调用一次flask db migrate生成迁移文件,自动检测models.py的模型flask db upgrade执行迁移文件中的升级(执行模型的建表,表字段更新等等)flask db downgrade损行迁移文件中的降级 7.查看数据库内容,第一次使用需要下载数据库驱动,自己download下载

4. 模型操作

I.创建模型

如果无__tablename__属性,表名为对应模型小写,即Person -> person

class Person(db.Model):

__tablename__ = 'person'

id = db.column(db.Integer, primary_key=True)

nane = db.column(db.string(16), unique=True)

字段类型

类型名Python模型说明IntegerInt普通整数,一般是32位SmallintegerInt取值范围小的整数一般是16位BigintegerInt或long不限制精度的整数Floatfloat浮点数Numericdecimal.Decimal定点数Stringstr变长字符串Textstr长字符串,对较长或不限长字符串做了优化Unicodeunicode变长Unicode字符串Unicodeunicode变长Unicode字符串,对较长或不限长字符串做了优化Booleanbool布尔值Datedatetime.date日期Timedatetime.time时间DateTimedatetime.datetime日期和时间Intervaldatetime.timedelta时间间隔LargeBinarystr二进制文件 常见约束

选项名说明primary_key如果设为True ,这列就是表的主键unique如果设为True ,这列不允许出现重复的值index如果设为True ,为这列创建索引提升查询效率nullable如果设为True ,这列允许使用空值:如果设为False ,这列不允许使用空值default为这列定义默认值

II. 单表操作

增加数据 # 增:添加数据

@blue.route('/useradd/')

def user_add():

# 一次添加一条数据

# u = User()

# u.name = 'kun'

# u.age = 25

# db.session.add(u) # 将u对象添加到session中

# db.session.commit() # 同步到数据库中

# 一次添加多条数据

users = []

for i in range(10, 30):

u = User()

u.name = '小冰' + str(i)

u.age = i

users.append(u)

try:

db.session.add_all(users)

db.session.commit() # 事务提交

except Exception as e:

db.session.rollback() # 回滚

db.session.flush() # 清空缓存

return 'fail' + str(e)

return 'success!'

删除数据 # 删:删除数据

# 找到要删除的数据,然后删除

@blue.route('/userdel/')

def user_del():

u = User.query.first() # 查询第一条数据

db.session.delete(u)

db.session.commit()

return 'success!

修改数据 # 改:修改数据

@blue.route('/userupdate/')

def user_update():

u = User.query.first()

u.age = 1000

db.session.commit()

return 'success!'

查询数据

all():返回所有数据,返回列表 users = User.query.all()

print(users, type(users)) # [...]

print(User.query, type(User.query)) #

filter() : 过滤,类似SQL中的where users = User.query.filter()

print(users, type(users)) # 查询集 可以继续.filter()...

print(list(users))

get(key): 查询到对应主键的数据对象,主键不存在返回None user = User.query.get(8)

print(user, type(user)) # 小冰15

print(user.name, user.age) # 获取数据的属性值

user.age = 15

db.session.commit()

filter() : 类似SQL中的where,filter_by() : 用于等值操作中的过滤。注意==和= # filter() : 类似SQL中的where

# filter_by() : 用于等值操作中的过滤

users = User.query.filter(User.age == 21)

users = User.query.filter_by(age=21)

users = User.query.filter(User.age > 21) # 可以用于非等值操作

print(list(users), type(users))

first() : 第一条数据,first_or_404() : 第一条数据,如果不存在则抛出404错误 user = User.query.first()

user = User.query.filter_by(age=100).first_or_404()

print(user)

count() : 统计查询集中的数据条数 count = User.query.count()

users = User.query.filter()

print(count, users.count())

limit() : 查询前几条数据,offset() : 跳过前几条 (可以用于手动分页) users = User.query.offset(3).limit(4)

print(list(users))

order_by() : 排序,默认升序(asc),降序使用desc users = User.query.order_by(desc('age'))

print(list(users))

逻辑运算:and_():且,or_():或,not_:非、取反, 默认是且操作 users = User.query.filter(User.age > 20, User.age < 25)

users = User.query.filter(and_(User.age > 20, User.age < 25)) # 默认就是且操作and_

users = User.query.filter(or_(User.age > 25, User.age < 20))

users = User.query.filter(not_(or_(User.age > 25, User.age < 20)))

print(list(users))

查询属性 User(类)属性上的方法 # contains(x) : 模糊查询,包含x子串,类似SQL的like

users = User.query.filter(User.name.contains('3'))

# in_([...]) : 其中之一

users = User.query.filter(User.age.in_([10, 25, 30, 40, 50]))

# startswith(x): 以x子串开头,endswith(x): 以x子串结尾

users = User.query.filter(User.name.startswith('小'))

users = User.query.filter(User.name.endswith('9'))

# __gt__ : 大于

# __ge__ : 大于等于

# __lt__ : 小于

# __le__ : 等于

users = User.query.filter(User.age.__gt__(20))

print(list(users))

分页(翻页查询)

手动翻页 # 1. 手动翻页

# offset().limit()

# 数据 1-20

# 页码:page = 1

# 每页显示数量:per_page = 5

# 总数:total=20

# 总页数:pages = 4

# page=1 : 1 2 3 4 5 => offset(0*5).limit(5)

# page=2 : 6 7 8 9 10 => offset(1*5).limit(5)

# ...

# page=n ((n-1)*5<=total) => offset((n-1)*5).limit(5)

# page=n ((n-1)*5>total) => offset((pages-1)*5).limit(5)

paginate对象实现分页 @blue.route('/userpaginate/')

def user_paginate():

# 页码:默认显示第一页

page = int(request.args.get('page', default=1))

# per_page: 每页显示数量

per_page = int(request.args.get('per_page', 5))

# print(page,type(page))

# print(per_page,type(per_page))

# paginate()

p = User.query.paginate(page=page, per_page=per_page, error_out=False)

# paginate对象的属性:

# items:返回当前页的内容列表

print(p.items)

# has_next:是否还有下一页

print(p.has_next)

# has_prev:是否还有上一页

print(p.has_prev)

# next(error_out=False):返回下一页的Pagination对象

print(p.next(error_out=False).items)

# prev(error out=Faise):返回上一页的Pagination对象

print(p.prev(error_out=False).items)

# page:当前页的页码(从1开始))

print(p.page)

# pages:总页数

print(p.pages)

# per_page:每页显示的数量

print(p.per_page)

# prev_num: 上一页页码数

print(p.prev_num)

# next_num: 下一页页码数

print(p.next_num)

# total:查询返回的记录总数

print(p.total)

return render_template('paginate.html',p=p)

paginate对象属性及方法:

属性说明items返回当前也的内容列表has_prev是否有上一页has_next是否有下一页next()返回下一页的paginate对象prev()返回上一页的paginate对象page当前的页码(1开始)pages总页数per_page每页显示数量prev_num上一页页码数next_num下一页页码数total查询数据(记录)总数 III. 多表操作 一对多

一个班级对应多个学生

from .exts import db

# 多表关系

# ------------ 一对多 ------------ #

# 班级:学生 = 1:N

# 班级表

class Grade(db.Model):

# 表名

__tablename__ = 'grade' # 表名

# 定义表字段

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(30), unique=True)

# 建立关联

# 第一个参数:关联的模型名(表)

# 第二个参数:反向引用的名称(对应的__tablename__),grade对象,让student去反过来得到grade对象的名称

# 第三个参数:懒加载

# 这里的students不是字段

students = db.relationship('Student', backref='grade', lazy=True)

class Student(db.Model):

__tablename__ = 'student'

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(30), unique=True)

age = db.Column(db.Integer)

# 外键

gradeid = db.Column(db.Integer, db.ForeignKey(Grade.id))

注意:

外键写在多的一方,在学生类(Student)中写 gradeid = db.Column(db.Integer, db.ForeignKey(Grade.id))并且要班级类(Grade)中建立联系 students = db.relationship('Student', backref='grade', lazy=True) 多对多

用户收藏电影 N:M,本质是多个一对多

# ------------ 多对多 ------------ #

# 用户收藏电影

# 用户 :电影 = N:M

# 中间表(写在最上面)

collect = db.Table(

'collects', # 表名

db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),

db.Column('movie_id', db.Integer, db.ForeignKey('movie.id'), primary_key=True)

)

# 用户表

class UserModel(db.Model):

__tablename__ = 'user'

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(30))

age = db.Column(db.Integer)

# 电影表

class MovieModel(db.Model):

__tablename__ = 'movie'

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(30))

# 关联属性 users

# secondary=collect : 设置中间表

users = db.relationship('UserModel', backref='movies', lazy='dynamic', secondary=collect)

# lazy属性;

# 懒加载,可以延迟在使用关联属性的时候才建立关联

# lazy = 'dynamic':会返回一个query对象(查询集),可以继续使用其他查询方法,如all().

# lazy = 'select ':首次访问到属性的时候,就会全部加载该属性的数据.

# lazy = 'joined " :在对关联的两个表进行join操作,从而获取到所有相关的对象

# lazy=True:返回一个可用的列表对象,同select

注意:

使用db.table()创建中间表

第一个参数字符串表示中间表的名字后面的参数列表:db.Column('tablename_id', db.Integer, db.ForeignKey('tablename.id'), primary_key=True)表示要绑定的外键 在任意一个非中间表建立联系(relationship) users = db.relationship('UserModel', backref='movies', lazy='dynamic', secondary=collect)

users:MovieModel中的属性,用来记录该电影被哪些用户所收藏 db.relationship:

第一个参数:字符串,写要关联的类第二个参数:backref=movies,反向引用另外模型类(表),值填入另外模型类的__tablename__的值即可第三个参数:懒加载,可以延迟在使用关联属性的时候才建立关联

lazy = 'dynamic':会返回一个query对象(查询集),可以继续使用其他查询方法,如all().lazy = 'select':首次访问到属性的时候,就会全部加载该属性的数据.lazy = 'joined' :在对关联的两个表进行join操作,从而获取到所有相关的对象lazy=True:返回一个可用的列表对象,同select

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。