Flask后端笔记(四)数据库的使用、查询等操作

数据库的设置

在这里插入图片描述

Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在表中,表用来给应用的实体建模,表的列数是固定的,行数是可变的。它使用结构化的查询语言。关系型数据库的列定义了表中表示的实体的数据属性。比如:商品表里有name、price、number等。 Flask本身不限定数据库的选择,你可以选择SQL或NOSQL的任何一种。也可以选择更方便的SQLALchemy,类似于Django的ORM。SQLALchemy实际上是对数据库的抽象,让开发者不用直接和SQL语句打交道,而是通过Python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升。

SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。

数据库安装

安装服务端

sudo apt-get install mysql-server
安装客户端

sudo apt-get install mysql-client
sudo apt-get install libmysqlclient-dev

数据库的基本命令

登录数据库

mysql -u root -p
创建数据库,并设定编码

create database <数据库名> charset=utf8;
显示所有数据库

show databases;

在Flask中使用mysql数据库

需要安装一个flask-sqlalchemy的扩展。
pip install flask-sqlalchemy
要连接mysql数据库,仍需要安装flask-mysqldb

pip install flask-mysqldb
或者
pip install MySQL-Python(Python2优先安装)

使用Flask-SQLAlchemy管理数据库

使用Flask-SQLAlchemy扩展操作数据库,首先需要建立数据库连接。数据库连接通过URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中。

对比下Django和Flask中的数据库设置:

Django的数据库设置:
在这里插入图片描述

Flask的数据库设置:

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test3'

常用的SQLAlchemy字段类型

类型名python中类型说明
Integerint普通整数,一般是32位
SmallIntegerint取值范围小的整数,一般是16位
BigIntegerint或long不限制精度的整数
Floatfloat浮点数
Numericdecimal.Decimal普通整数,一般是32位
Stringstr变长字符串
Textstr变长字符串,对较长或不限长度的字符串做了优化
Unicodeunicode变长Unicode字符串
UnicodeTextunicode变长Unicode字符串,对较长或不限长度的字符串做了优化
Booleanbool布尔值
Datedatetime.date时间
Timedatetime.datetime日期和时间
LargeBinarystr二进制文件

常用的SQLAlchemy列选项

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

常用的SQLAlchemy关系选项

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

demo.py

# coding:utf-8

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)


class Config(object):
    """配置参数"""
    # sqlalchemy的配置参数
    SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/db_python04"

    # 设置sqlalchemy自动更跟踪数据库
    SQLALCHEMY_TRACK_MODIFICATIONS = True


app.config.from_object(Config)

# 创建数据库sqlalchemy工具对象
db = SQLAlchemy(app)


class Role(db.Model):
    """用户角色/身份表"""
    __tablename__ = "tbl_roles"
	# 定义列对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)
    users = db.relationship("User", backref="role")
    
	#repr()方法显示一个可读字符串
    def __repr__(self):
        """定义之后,可以让显示对象的时候更直观"""
        return "Role object: name=%s" % self.name


# 表名的常见规范
# ihome -> ih_user   数据库名缩写_表名
# tbl_user  tbl_表名
# 创建数据库模型类
class User(db.Model):
    """用户表"""
    __tablename__ = "tbl_users"  # 指明数据库的表名

    id = db.Column(db.Integer, primary_key=True)  # 整型的主键,会默认设置为自增主键
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(128), unique=True)
    password = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))

    def __repr__(self):
        return "User object: name=%s" % self.name


if __name__ == '__main__':
    # 清除数据库里的所有数据
    db.drop_all()

    # 创建所有的表
    db.create_all()

    # 创建对象
    role1 = Role(name="admin")
    # session记录对象任务
    db.session.add(role1)
    # 提交任务到数据库中
    db.session.commit()

    role2 = Role(name="stuff")
    db.session.add(role2)
    db.session.commit()

    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=role1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=role2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=role2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=role1.id)

    # 一次保存多条数据
    db.session.add_all([us1, us2, us3, us4])
    db.session.commit()

查询操作

# 查询所有
Role.query.all()
Out[2]: [<db_demo.Role at 0x10388d190>, <db_demo.Role at 0x10388d310>]

In [3]: li = Role.query.all()

In [4]: li
Out[4]: [<db_demo.Role at 0x10388d190>, <db_demo.Role at 0x10388d310>]

In [5]: r = li[0]

In [6]: type(r)
Out[6]: db_demo.Role

In [7]: r.name
Out[7]: u'admin'

# 查询第一条
In [8]: Role.query.first()
Out[8]: <db_demo.Role at 0x10388d190>

In [9]: r = Role.query.first()

In [10]: r.name
Out[10]: u'admin'

#  根据主键id获取对象
In [11]: r = Role.query.get(2)

In [12]: r
Out[12]: <db_demo.Role at 0x10388d310>

In [13]: r.name
Out[13]: u'stuff'

# 另一种查询方式
In [15]: db.session.query(Role).all()
Out[15]: [<db_demo.Role at 0x10388d190>, <db_demo.Role at 0x10388d310>]

In [16]: db.session.query(Role).get(2)
Out[16]: <db_demo.Role at 0x10388d310>

In [17]: db.session.query(Role).first()
Out[17]: <db_demo.Role at 0x10388d190>

常用的SQLAlchemy查询过滤器

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

常用的SQLAlchemy查询执行器

方法说明
all()以列表形式返回查询的所有结果
first()返回查询的第一个结果,如果未查到,返回None
first_or_404()返回查询的第一个结果,如果未查到,返回404
get()返回指定主键对应的行,如不存在,返回None
get_or_404()返回指定主键对应的行,如不存在,返回404
count()返回查询结果的数量
paginate()返回一个Paginate对象,它包含指定范围内的结果

查询:过滤器

In [18]: User.query.filter_by(name="wang")
Out[18]: <flask_sqlalchemy.BaseQuery at 0x1038c90d0>

In [19]: User.query.filter_by(name="wang").all()
Out[19]: [<db_demo.User at 0x1038c87d0>]

In [20]: User.query.filter_by(name="wang").first()
Out[20]: <db_demo.User at 0x1038c87d0>

In [21]: user = User.query.filter_by(name="wang").first()

In [22]: user.name
Out[22]: u'wang'

In [23]: user.email
Out[23]: u'wang@163.com'

In [24]: User.query.filter_by(name="wang", role_id=1).first()
Out[24]: <db_demo.User at 0x1038c87d0>

In [25]: User.query.filter_by(name="wang", role_id=2).first()

In [26]: user = User.query.filter_by(name="wang", role_id=2).first()

In [27]: type(user)
Out[27]: NoneType

In [28]: user = User.query.filter(User.name=="wang", User.role_id==1).first()

In [29]: user
Out[29]: <db_demo.User at 0x1038c87d0>

In [30]: user.name
Out[30]: u'wang'


逻辑非,返回名字不等于wang的所有数据。

User.query.filter(User.name!='wang').all()
逻辑非

逻辑与,需要导入and,返回and()条件满足的所有数据。

from sqlalchemy import and_
User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()

and_

逻辑或,需要导入or_

from sqlalchemy import or_
User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()

or_

not_ 相当于取反

from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()

在这里插入图片描述
偏移

# offset偏移  跳过几条
In [36]: User.query.offset(2).all()
Out[36]: [<db_demo.User at 0x1038c0950>, <db_demo.User at 0x1038ef310>]

In [37]: li = User.query.offset(2).all()

In [38]: li[0].name
Out[38]: u'chen'

In [39]: li[1].name
Out[39]: u'zhou'


In [42]: li = User.query.offset(1).limit(2).all()

In [43]: li
Out[43]: [<db_demo.User at 0x1038fd990>, <db_demo.User at 0x1038c0950>]

In [44]: li[0].name
Out[44]: u'zhang'

In [45]: li[1].name
Out[45]: u'chen'

排序

In [50]: User.query.order_by("-id").all()
Out[50]:
[<db_demo.User at 0x1038ef310>,
 <db_demo.User at 0x1038c0950>,
 <db_demo.User at 0x1038fd990>,
 <db_demo.User at 0x1038c87d0>]

In [51]:

In [51]: li = User.query.order_by(User.id.desc()).all()

In [52]: li
Out[52]:
[<db_demo.User at 0x1038ef310>,
 <db_demo.User at 0x1038c0950>,
 <db_demo.User at 0x1038fd990>,
 <db_demo.User at 0x1038c87d0>]

In [53]: li[0].name
Out[53]: u'zhou'

In [54]: li[3].name
Out[54]: u'wang'

分组

In [55]: from sqlalchemy import func

In [56]: db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id)
Out[56]: <flask_sqlalchemy.BaseQuery at 0x103a38050>

In [57]: db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id).all()
Out[57]: [(1L, 2L), (2L, 2L)]



在这里插入图片描述

从角色查询用户和从用户查询角色

In [61]: ro = Role.query.get(1)

In [62]: type(ro)
Out[62]: db_demo.Role

In [63]: ro.users
Out[63]: [<db_demo.User at 0x1038c87d0>, <db_demo.User at 0x1038ef310>]

In [64]: ro.users[0].name
Out[64]: u'wang'

In [65]: ro.users[1].name
Out[65]: u'zhou'


In [67]: user
Out[67]: <db_demo.User at 0x1038c87d0>

In [68]: user.role_id
Out[68]: 1L

In [69]: Role.query.get(user.role_id)
Out[69]: <db_demo.Role at 0x10388d190>

In [70]: user.role
Out[70]: <db_demo.Role at 0x10388d190>

In [71]: user.role.name
Out[71]: u'admin'

优化查询显示
在这里插入图片描述

在这里插入图片描述
更新

# 更新
In [14]: User.query.filter_by(name="zhou").update({"name": "python", "email": "python@itast.cn"})
Out[14]: 1L

In [15]: db.session.commit()

In [16]:

删除



# 删除
In [16]: user = User.query.get(3)

In [17]: db.session.delete(user)

In [18]: db.session.commit()

In [19]:

先查询后更新或删除
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值