flask数据操纵

2023-01-31 00:01:49 flask 数据 操纵

Django框架中内部已经提供ORM这样的框架,来实现对象关系映射,方便我们操作数据库。如果想在flask中也达到这样效果,需要安装一个第三方来支持。
sqlAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。

安装

pip install flask-sqlalchemy

这里以Mysql数据库为例
安装pymysql

pip install pymysql

相关配置

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import pymysql

pymysql.install_as_MySQLdb()
app = Flask(__name__)
# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1:3306/db_flask'

# 数据库和模型类同步修改
app.config['SQLALCHEMY_TRACK_MODIFICATioNS'] = True

# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
# 管理app
db = SQLAlchemy(app)

字段类型

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

约束类型

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

关系类型

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

创建

在Flask-SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理。会话用db.session表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用commit()方法提交会话。
如果失败还可以回滚:db.rollback(),实现回话提交数据到以前的状态

模型类
"""
相关配置的代码 记得改为你自己的数据库
"""

class Type(db.Model):
    __tablename__ = 'tbl_type' # 表的名字 如果不写就以类名命名
    id = db.Column(db.Integer,primary_key=True) # 主建
    name = db.Column(db.String)
     id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(32), unique=True)  # 名字

    # 数据库中不存在的字段,只是为了查找和反向查找。
    # backref:在关系的另一模型中添加反向引用
    heros = db.relationship("Hero", backref='type')


# 英雄
class Hero(db.Model):
    # 表名
    __tablename__ = 'tbl_heros'
    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(64), unique=True)  # 名字
    gender = db.Column(db.String(64))  # 性别

    # 外键 一个射手对应很多英雄
    type_id = db.Column(db.Integer, db.ForeignKey("tbl_types.id"))

if __name__ == "__main__":
    db.create_all()  # 创建表

    type1 = Type(name='射手')
    db.session.add(type1)  # 添加到会话
    db.session.commit()  # 提交

    type2 = Type(name='坦克')
    db.session.add(type2)
    db.session.commit()

    type3 = Type(name='法师')
    type4 = Type(name='刺客')
    db.session.add_all([type3, type4])  # 添加多个
    db.session.commit()

    hero1 = Hero(name='后羿', gender='男', type_id=type1.id)
    hero2 = Hero(name='程咬金', gender='男', type_id=type2.id)
    hero3 = Hero(name='王昭君', gender='女', type_id=type3.id)
    hero4 = Hero(name='安琪拉', gender='女', type_id=type3.id)
    hero5 = Hero(name='兰陵王', gender='男', type_id=type4.id)

    db.session.add_all([hero1, hero2, hero3, hero4, hero5])  # 添加多个
    db.session.commit()

到你数据库查一下

查询

Flask-SQLAlchemy中常用过滤器:

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

Flask-SQLAlchemy中常用执行器:

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

这里举几个例子:
查全部分类:

Type.query.all()

根据分类过滤:

Type.query.filter_by(id = 1)

注意:
filter和 filter_by 的区别:

Type.query.filter(类.字段 == 条件) Type.query.filter_by(字段 = 条件)

逻辑与

Hero.query.filter_by(name='王昭君',type_id=3).first()

逻辑或

from sqlalchemy import or_
Hero.query.filter(or_(Hero.name.endswith('君'),Hero.type_id==3)).all()

排序

降序查询
Hero.query.order_by(Hero.id.desc()).all()
升序查询
Hero.query.order_by(Hero.id.asc()).all()

各种查询方法还有很多,大家可以去Google或是百度

更新

  • 第一种
    hero = Hero.query.get(1)
    hero.name = '伽罗'
    db.session.add(hero)
    db.session.commit()
  • 第二种
    Hero.query.filter_by(id=1).update({"name":"虞姬","gender":"女"})
    db.session.commit()

删除

hero = Hero.query.get(4)
db.session.delete(hero)
db.session.commit()

模型迁移

在Django框架开发过程中,我们对数据库字段添加或删除,直接修改模型类,然后进行迁移可以了,非常方便。我们也想让Flask框架支持这样的操作,就需要使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成。

安装插件

pip install Flask-Script
pip install flask-migrate

使用
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import pymysql
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager

pymysql.install_as_MySQLdb()
app = Flask(__name__)

# 通过脚本管理flask程序
manager = Manager(app)
"""
相关配置
"""
db = SQLAlchemy(app)

# 创建数据库迁移对象
Migrate(app, db)

# 向脚步管理添加数据库迁移命令 db指命令的别名
manager.add_command('db', MigrateCommand)


"""
模型代码
"""

初始化 只是在每个项目第一次生成迁移用到 以后就不用了

python3 app.py db init

app.py >> 你自己的文件名 db >> 上面指定的命令别名
在你的项目文件下 多出 migrations 的文件

生成迁移文件

Python app.py db migrate -m 'first create'
提示:
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.env] No changes in schema detected.

提交:
python flask_migrate_db.py db upgrade
ok 你的数据库已经有了数据

回退:

回退数据库时,需要指定回退版本号,由于版本号是随机字符串,为避免出错,建议先使用python flask_migrate_db.py db history命令查看历史版本的具体版本号,然后复制具体版本号执行回退。
python flask_migrate_db.py db downgrade base

python flask_migrate_db.py db downgrade 4cee71e47df3
4cee71e47df3 >>版本号

模型关系

在数据库中,我们知道数据关系大概有如下几种:一对一、一对多、多对多、自关联等。我们模型已经描述过了一对多,那么下面我们在用模型把其它关系也写出来。

一对一

# 文章模型
class Article(db.Model):
    # 表名
    __tablename__ = 'tbl_article'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    title = db.Column(db.String(128), unique=True)  # 名字
    
    # 方便查找,数据并不存在的字段
    content = db.relationship('Acontent', backref='article', uselist=False) #一对一需要把uselist设置为False


# 内容模型
class Acontent(db.Model):
    # 表名
    __tablename__ = 'tbl_acontent'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    content = db.Column(db.Text(4000))  # 名字
一对多
# 分类模型
class Category(db.Model):
    # 表名
    __tablename__ = 'tbl_category'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(32), unique=True)  # 名字
    # 方便查找,数据并不存在的字段
    article = db.relationship('Article', backref='category')


# 文章模型
class Article(db.Model):
    # 表名
    __tablename__ = 'tbl_article'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    title = db.Column(db.String(128), unique=True)  # 名字
    category_id = db.Column(db.Integer, db.ForeignKey('tbl_category.id'))  # 分类id
多对多
# 辅助表
tbl_tags = db.Table('tbl_tags',
                db.Column('tag_id', db.Integer, db.ForeignKey('tbl_tag.id')),
                db.Column('article_id', db.Integer, db.ForeignKey('tbl_article.id'))
                )

# 标签模型
class Tag(db.Model):
    # 表名
    __tablename__ = 'tbl_tag'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(32), unique=True)  # 名字


# 文章模型
class Article(db.Model):
    # 表名
    __tablename__ = 'tbl_article'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    title = db.Column(db.String(128), unique=True)  # 名字
    category_id = db.Column(db.Integer, db.ForeignKey('tbl_category.id'))  # 分类id
    # 方便查找,数据并不存在的字段
    content = db.relationship('Acontent', backref='article')
    tags = db.relationship('Tag', secondary=tbl_tags, backref='articles')
    # secondary=tbl_tags, tbl_tags->辅助表的名字 注意!!!
自关联
# 地区模型
class Area(db.Model):
    # 表名
    __tablename__ = "tbl_area"
    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.Text, nullable=False)  # 地区名字
    parent_id = db.Column(db.Integer, db.ForeignKey("tbl_area.id"))  # 父评论id

    # 方便查找,数据并不存在的字段
    parent = db.relationship("Area", remote_side=[id])  # 自关联需要加remote_side

flask 数据库的有关操作就到此结束了,有什么问题可以给我留言,看到会回复大家的
喜欢就点播关注吧-_-!

相关文章