2020-06-10--flask06--flask基础06

2020-06-11  本文已影响0人  program_white

数据库的连接

在昨天使用flask-sqlalchemy中的SQLAlchemy连接了数据库。

#mysql数据库信息
mysql = 'mysql'
username = 'root'
password = 'root'
host = 'localhost'
port = '3306'
db = 'test3'
# mysql://(用户名):(密码)@地址/数据库名
mysqlpath = '{}://{}:{}@{}:{}/{}'.format(mysql,username,password,host,port,db)
#设置数据库的路径
app.config['SQLALCHEMY_DATABASE_URI'] = mysqlpath
#关联app
db = SQLAlchemy(app)

app中常见的数据库设置

一些重要的设置:

#设置数据库信息
app.config['SQLALCHEMY_DATABASE_URI'] = 数据库信息
#动态追踪设置,不设置会警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#显示原始sql
app.config['SQLALCHEMY_ECHO'] = True
#设置每次请求结束后自动提交数据库的改动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True

除了这些配置之外还有一些配置:

选项 说明
SQLALCHEMY_DATABASE_URI 用于连接的数据库 URI 。例如:sqlite:////tmp/test.db 或 [mysql://username:password@server/db]
SQLALCHEMY_BINDS 一个映射 binds 到连接 URI 的字典。更多 binds 的信息见 用 Binds 操作多个数据库
SQLALCHEMY_ECHO 如果设置为 Ture , SQLAlchemy 会记录所有 发给 stderr 的语句,这对调试有用
SQLALCHEMY_RECORD_QUERIES 可以用于显式地禁用或启用查询记录。查询记录 在调试或测试模式自动启用。更多信息见 get_debug_queries()
SQLALCHEMY_NATIVE_UNICODE 可以用于显式禁用原生 unicode 支持。当使用不合适的指定无编码的数据库默认值时,这对于 一些数据库适配器是必须的(比如 Ubuntu 上某些版本的 PostgreSQL )
SQLALCHEMY_POOL_SIZE 数据库连接池的大小。默认是引擎默认值(通常 是 5 )
SQLALCHEMY_POOL_TIMEOUT 设定连接池的连接超时时间。默认是 10
SQLALCHEMY_POOL_RECYCLE 多少秒后自动回收连接。这对 MySQL 是必要的, 它默认移除闲置多于 8 小时的连接。注意如果 使用了 MySQL , Flask-SQLALchemy 自动设定这个值为 2 小时。

model层模型字段,字段约束,表间关系

类型名 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 二进制文件

约束字段和表间关系

Flask-SQLAlchemy不自动设置表内的字段的约束,因此需要在设计数据字段时自行添加。
那么常见的约束字段有

选项名 说明
primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值
autoincrement 自增

表间关系字段

选项名 说明
backref 在关系的另一模型中添加反向引用,用于设置外键名称,在1内查n的
primary join 明确指定两个模型之间使用的联结条件
uselist 如果为False,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定多对多关系中关系表的名字
secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
lazy 指定如何加载相关记录。

lazy的可选值:

属性 说明
select 首次访问时按需加载
immediate 源对象加载后就加载
joined 加载记录,但使用联结
subquery 立即加载,但使用子查询
noload 永不加载
dynamic 不加载记录,但提供加载记录的查询

SQLAlchemy查询执行器及过滤器

执行器

执行器 说明
all() 以列表形式返回查询的所有结果
first() 返回查询的第一个结果,如果没有结果,则返回 None
first_or_404() 返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应
get() 返回指定主键对应的行,如果没有对应的行,则返回 None
get_or_404() 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应
count() 返回查询结果的数量
paginate() 返回一个 Paginate 对象,它包含指定范围内的结果

过滤器

过滤器 说明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

filter_by() 和 filter() 的最主要的区别:

模块 语法 ><(大于和小于)查询 and_和or_查询
filter_by() 直接用属性名,比较用= 不支持 不支持
filter() 用类名.属性名,比较用== 支持 支持

model层建表实例

那么现在我们建两个具有一对多关系的表:Role和User

#model类
#角色类
class Role(db.Model):
    #定义表名
    __tablename__ = 'roles'
    #id
    id = db.Column(db.Integer,primary_key=True)
    #name
    name = db.Column(db.String(64),unique=True)
    db.relationship('User',backref='role')

    def __repr__(self):
        return 'Role:{}'.format(self.name)

#用户类
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64),unique=True)
    email = db.Column(db.String(64),unique=True)
    password = db.Column(db.String(64))
    role_id = db.Column(db.Integer,db.ForeignKey('roles.id'))        #正向关联外键,role_id与roles表中的id关联

    def __repr__(self):
        return 'User:{}'.format(self.name)

在多的表中设置外键关联一表中的id字段。

在数据库中创建这两个表,并插入测试数据:

# 删除表
db.drop_all()
# 创建表
db.create_all()

# 填加数据
ro1 = Role(name='admin')
ro2 = Role(name='user')

db.session.add_all([ro1, ro2])
db.session.commit()   #提交

us1 = User(name='wang',email='wang@163.com',password='123456',role_id=ro1.id)
us2 = User(name='zhang',email='zhang@189.com',password='201512',role_id=ro2.id)
us3 = User(name='chen',email='chen@126.com',password='987654',role_id=ro2.id)
us4 = User(name='zhou',email='zhou@163.com',password='456789',role_id=ro1.id)
us5 = User(name='tang',email='tang@neuedu.com',password='158104',role_id=ro2.id)
us6 = User(name='wu',email='wu@gmail.com',password='5623514',role_id=ro2.id)
us7 = User(name='qian',email='qian@gmail.com',password='1543567',role_id=ro1.id)
us8 = User(name='liu',email='liu@neuedu.com',password='867322',role_id=ro1.id)
us9 = User(name='li',email='li@163.com',password='4526342',role_id=ro2.id)
us10 = User(name='sun',email='sun@163.com',password='235523',role_id=ro2.id)

db.session.add_all([us1,us2,us3,us4,us5,us6,us7,us8,us9,us10])
db.session.commit()

注:当插入数据执行完成后,可将这段代码注释掉,避免在操作完数据后,执行这段代码后,删除所有表,再次执行这段初始化的数据,

花样查询

数据库操作中,查询操作十分的复杂
以User表为例:


all_user = User.query.all()
first = User.query.first()
a = User.query.filter(User.name == 'wang').all()               #使用filter查询
a1 = User.query.filter_by(name = 'wang').all()                #使用filter_by查询
l = User.query.filter(User.name != 'wang').all()
#filter不支持使用 比较符
#过滤条件
User.name.endwith('g')

g = User.query.filter(User.name.endswith('g')).all()
# 使用filter查询name为wang并且密码为123456
b1 = User.query.filter(User.name == 'wang', User.password == '123456').all()  # 推荐
b2 = User.query.filter(User.name == 'wang').filter(User.password == '123456').all()
# 使用filter_by
b3 = User.query.filter_by(name='wang', password='123456').all()
k = User.query.filter(User.name != 'wang',User.password.endswith('6')).all()
k1 = User.query.filter(and_(User.name != 'wang',User.password.endswith('6'))).all()
c1 = User.query.filter(or_(User.name == 'wang', User.password == '201512')).all()
p = User.query.get(1)         #返回对象

注:只有first和get返回的是数据的对象,filter返回的是对象数组

删除和更新

1.删除数据时,首先要查到这条数据
具体的查询方法在查询中
举例:

    #删除User表中第一条数据
    first = User.query.first()        #查询第一条数据
    db.session.delete(first)      #删除它

数据库:
id为1的数据删除了


2.更新数据也是首先要查询到该数据

    #更新第一条数据
    first = User.query.first()   #查询要更新的数据
    first.name = 'lizhao'       #更新数据
    db.session.commit()      #提交

数据库:


数据库操作的提交

Flask-SQLAlchemy的增删改操作可以理解为是通过与数据库建立一个小型会话的方式进行的,下面介绍一下这些基于db = SQLAlchemy(app)的操作

操作 说明
create_all() 建表操作,db.create_all()
drop_all() 删除表操作,db.drop_all()
add_all() 插入操作,db.seesion.add_all([]),插入可选择使用list进行批量插入
commit() 提交操作,db.session.commit(),提交其语句以上的所有更改数据库内容的操作
delete() 删除操作,db.session.delete(),删除一条数据
    # 查询所有用户数据User.
    # 查询有多少个用户
    # 查询第1个用户
    # 查询id为4的用户[3种方式]
    # 查询名字结尾字符为g的所有数据[开始/包含]
    # 查询名字不等于wang的所有数据[2种方式]
    # 查询名字和邮箱都以 li 开头的所有数据[2种方式]
    # 查询password是 `123456` 或者 `email` 以 `neuedu.com` 结尾的所有数据
    # 查询id为 [1, 3, 5, 7, 9] 的用户列表
    # 查询name为liu的角色数据
    # 查询所有用户数据,并以邮箱排序
    # 每页3个,查询第2页的数据

答案:

from sqlalchemy import not_

from db_demo import *   #导入该包中的model类

# 查询所有用户数据User.
print(User.query.all())

# 查询有多少个用户
print(User.query.count())

# 查询第1个用户
print(User.query.first())

# 查询id为4的用户[3种方式]
print(User.query.get(4))
print(User.query.filter(User.id == 4).all())
print(User.query.filter_by(id = 4).all())

# 查询名字结尾字符为g的所有数据[开始/包含]
print(User.query.filter(User.name.endswith('g')).all())
print(User.query.filter(User.name.startswith('g')).all())
print(User.query.filter(User.name.contains('g')).all())

# 查询名字不等于wang的所有数据[2种方式]
print(User.query.filter(User.name != 'wang').all())
print(User.query.filter(not_(User.name == 'wang')).all())

# 查询名字和邮箱都以 li 开头的所有数据[2种方式]
print(User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all())
print(User.query.filter(and_(User.name.startswith('li'),User.email.startswith('li'))).all())

# 查询password是 `123456` 或者 `email` 以 `neuedu.com` 结尾的所有数据
print(User.query.filter(or_(User.password == '123456',User.email.endswith('neuedu.com'))).all())

# 查询id为 [1, 3, 5, 7, 9] 的用户列表
list = [1,3,5,7,9]
print(User.query.filter(User.id.in_(list)).all())


# 查询name为liu的角色数据
users = User.query.filter_by(name = 'liu').all()
for user in users:
    print(user.role)

#查询id为1的角色所有的用户
role = Role.query.get(1)
print(role.user)


# 查询所有用户数据,并以邮箱排序
all_user = User.query.order_by('email').all()
print(all_user)

# 每页3个,查询第2页的数据
user = User.query.paginate(page=2,max_per_page=3)    #page:页码,max_per_page:每页的个数
print(user.items)   #当前页的内容
print(user.page)    #当前页码
print(user.pages)   #分的总页数
上一篇下一篇

猜你喜欢

热点阅读