<Flask>-sqlalchemy操作数据库

<Flask>-sqlalchemy操作数据库_db.drop_all()_kobe_OKOK_的博客-CSDN博客

1 简述

操作数据分为数据库模型的创建于数据库迁移,数据库的创建依赖于flask-sqlalchemy

  1. 一对多模型
  2. 多对多模型
  3. 自关联一对多模型
  4. 自关联多对多模型


2-导包与配置

import flask_sqlalchemy improt SQLALCHEMY
import flask_script import Manager
import flask_migrate import Migrate, MigrateCommand

# 数据库的基本配置:
SQLALCHEMY_DATABASE_URI = "database connnection string"
SQLALCHEMY_TRACK_MODIFICATIONS =False


3-增删改查

3.1 增

# 导包
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy

# 初始化app
app = Flask(__name__)
# 配置app数据库属性
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:root@localhost:3306/flask1227?charset=utf8"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 配置自动提交,视图函数中操作数据库可以不使用db.session.commit()自动进行提交
#app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True

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

# 新建模型类、一个模型对应数据库中的一张表、集成db.Model
class Person(db.Model):
    # 如果不定义__tablename__类属性,数据库中的表名是类名(Person)如果定义,数据库的表名被改成这个属性
    __tablename__ = 'persons'
    # 定义主键字段
    id = db.Column(db.Integer, primary_key=True)
    # 定义字段
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)

    # 重写__repr__方法方便查看查询后打印的对象信息
    def __repr__(self):
        return "<person>:%s<age>:%d"%(self.name, self.age)


if __name__ == '__main__':
    # 删除表
    db.drop_all()
    # 创建表
    db.create_all()
    # 实例化一个对象,每实例化一个对象都对应表中的一行数据(entry)
    person1 = Person(name='小张', age=16)
    # 增加数据方法1:
    db.session.add(person1)
    db.session.commit()
    # 增加数据方法2:
    person2 = Person(name="小李", age=24)
    person3 = Person(name="小赵", age=46)
    person4 = Person(name="小红", age=12)
    db.session.add_all([person2, person3, person4])
    db.session.commit()
    #db.session.commit()
    #app.run(debug=True)

3.2 删

    person = Person.query.get(1)
    db.session.delete(person)
    db.session.commit()

3.3 改

    person = Person.query.get(1)
    print(person.name)
    # 小张
    person.name = "张三"
    print(person.name)
    # 张三
    # 只有执行了下面这条语句数据库才会改变
    db.session.commit()

3.4 查

    """ 插入测试数据
    # 删除表
    db.drop_all()
    # 创建表
    db.create_all()
    # 实例化一个对象,每实例化一个对象都对应表中的一行数据(entry)
    #person1 = Person(name='小张', age=16)
    # 增加数据方法1:
    #db.session.add(person1)
    #db.session.commit()
    # 增加数据方法2:
    # person2 = Person(name="小李", age=24)
    # person3 = Person(name="小赵", age=46)
    # person4 = Person(name="小红", age=12)
    # db.session.add_all([person2, person3, person4])
    # db.session.commit()
    #db.session.commit()
    #app.run(debug=True)
    role1 = Role(name="admin")
    role2 = Role(name="user")
    db.session.add_all([role1, role2])
    db.session.commit()

    user1 = User(name="wangda", phone="13000002314", email="[email protected]", password="fhasr", c_id=1)
    user2 = User(name="lier", phone="13540000314", email="[email protected]", password="3414321", c_id=1)
    user3 = User(name="zhangsan", phone="143000234321", email="[email protected]", password="asdfvz", c_id=2)
    user4 = User(name="lisi", phone="13043005414", email="[email protected]", password="fsagas", c_id=2)
    user5 = User(name="liuwu", phone="140005322314", email="[email protected]", password="jhggf", c_id=2)
    user6 = User(name="maliu", phone="16504302314", email="[email protected]", password="jgfhjgf", c_id=2)
    user7 = User(name="tainqi", phone="180097002314", email="[email protected]", password="fhtrytrasr", c_id=2)
    user8 = User(name="zhuoba", phone="13004302314", email="[email protected]", password="fjg", c_id=1)
    user9 = User(name="nianjiu", phone="14505002314", email="[email protected]", password="rtetr", c_id=2)

    db.session.add_all([user1,user2,user3,user4,user5,user6,user7,user8,user9])
    db.session.commit()
    """
    # 查询所有用户数据
    total_user = User.query.all() ->list
    print(total_user)
    # 查询有多少个用户
    total_count = User.query.count() -> int 
    print(total_count)
    # 查询第1个用户
    first_user1 = User.query.all()[0]
    print(first_user1)
    first_user2 = User.query.first()
    print(first_user2)
    # 查询id为4的用户[3种方式]
    user4_1 = User.query.get(4)
    print(user4_1)
    user4_2 = User.query.filter(User.id==4).first()
    print(user4_2)
    user4_3 = User.query.filter_by(id=4).first()
    print(user4_3)
    # 查询名字结尾字符为g的所有数据[开始 / 包含]
    user_1 = User.query.filter(User.name.startswith('g')).all()
    print(user_1)
    user_2 = User.query.filter(User.name.endswith('g')).all()
    print(user_2)
    user_3 = User.query.filter(User.name.contains('g')).all()
    print(user_3)
    # 查询名字不等于wang的所有数据[2种方式]
    user_1 = User.query.filter(User.name != 'wang').all()
    print(user_1)
    user_2 = User.query.filter(not(User.name == 'wang')).all()
    print(user_2)
    # 查询名字和邮箱都以li开头的所有数据[2种方式](2个条件与查询)
    user_1 = User.query.filter(User.name == 'li', User.email.startswith('li')).all()
    print(user_1)
    user_2 = User.query.filter(and_(User.name.startswith('wa'), User.email.startswith('21'))).all()
    print(user_2)
    # 查询password是`123456`或者`email`以`itheima.com`结尾的所有数据
    user = User.query.filter(or_(User.password=="jhggf", User.email.endswith("qq.com"))).all()
    print(user)
    # 查询id为[1, 3, 5, 7, 9]的用户列表
    user_list =User.query.filter(User.id.in_([1,3,5,7,9])).all()
    print(user_list)
    # 查询name为liu的角色数据
    role = Role.query.get(User.query.filter(User.name=='zhangsan').first().c_id)
    print(role)
    # 查询所有用户数据,并以邮箱排序
    user = User.query.order_by(User.email).all()
    print(user)
    [<User>:zhuoba, <User>:nianjiu, <User>:lier, <User>:lisi, <User>:wangda, <User>:liuwu, <User>:tainqi, <User>:maliu, <User>:zhangsan]

    user_1 = User.query.order_by(User.email.desc()).all()
    print(user_1)
    [<User>:zhangsan, <User>:maliu, <User>:tainqi, <User>:liuwu, <User>:wangda, <User>:lier, <User>:lisi, <User>:nianjiu, <User>:zhuoba]
    # 每页3个,查询第2页的数据
    paginate = User.query.paginate(2,3,False)
    print(paginate.items)
    print(paginate.pages)
    print(paginate.page)
    paginate = User.query.paginate(page, per_page, Error_out)
    parems:page:共有多少页
           per_page:每页多少条数据
           Error_out:查不到不报错

4 一对多模型

4.1 理解

        生活中有很多一对多的案例,比如说:人和手机,一个人可以有多台手机,人就是一方,手机就是多方,一种角色可以有多个用户,每个用户都有唯一的一个角色。当你需要查询某一个角色有哪些用户,可以这样写代码:

role = Role.query.get(1)
user = User.query.filter(User.c_id == role.id).all()

        同样,当你知道一个用户,想知道这个用户扮演什么角色的时候,可以这样写代码:

user = User.query.get(1)
role = User.query.get(user.c_id)

        这样写代码虽然也能够实现,但是相对麻烦,下面通过在”一方“中添加关系属性,更好的实现“一对多关系模型”

4.2 代码实现

# 一方(关系属性写在一方)
class Role(db.Model):
    __tablename__ = "roles"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    users = db.relationship("User",backref="role")
    #users = db.relationship("User", backref="role", lazy="dynamic")
    # output: 
    # role = Role.query.get(1)
    # role.users.all()
# db.relationship("多方模型类", backref="名字", lazy="")
    #param1:多方模型类
    #param2:backref:反向引用,角色.名字 查询你角色中的多个类
    # param3: lazy:默认是”subquery“:当获取其中一个角色的时候,其角色的所有用户也被自动查询出来,这样会造成性能浪费
    ”dynamic“动态的意思:不会自动查询出包含的所有多类,而是返回一个BaseQuery对象,通过执行器(all(),first())等拿到需要的数据。

    

# 多方(外键一般写在多方)
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    r_id = db.Column(db.Integer, db.ForeignKey("roles.id"))
    
    
# 查询一个角色中的所有用户
role = Role.query.get(1)
role.users
# [<User>:wangda, <User>:lier, <User>:zhuoba]


# 查询某个用户的角色信息
user = User.query.get(1)
user.role
# <Role>:admin

5 多对多模型

5.1 理解

学生网上选课
老师与授课班级
用户与新闻收藏关系
多对多之间,需要使用一张单独表去记录两张表之间的关系
外键写在多方,多对多可以拆分成两个一对多
其中两个单一表分别对应的一方,中间表是多方
所以中间表中应该写两个外键,关系属性可以写在任一方内

5.2 代码实现

# 创建中间表
tb_student_course = db.Table(
    "tb_student_course",
    db.Column("id", db.integer,primary_key=True),
    db.Column('student_id', db.Integer, db.Foreignkey("students.id")),
    db.Column('course_id', db.Integer,db.Foreignkey("courses.id"))
)

# 创建学生类
class Student(db.Model):
    __tablename__ = "students"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    courses = db.relationship("Course", backref='students', secondary='tb_student_course')

# 为了方便查看,重写__repr__方法
    def __repr__(self):
        return "<student:%s>"self.name

# 创建课程表
class Course(db.Model):
    __tablename__ = "courses"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    
    def __repr__(self):
        return "<Course:%s>"self.name

# 添加新数据
stu1 = Student(name='张三')
stu2 = Student(name='李四')
stu3 = Student(name='王五')

cou1 = Course(name='物理')
cou2 = Course(name='化学')
cou3 = Course(name='生物')

stu1.courses = [cou1, cou2]
stu2.courses = [cou2]
stu3.courses = [cou1, cou2, cou3]

db.session.commit([stu1, stu2, stu3])
db.session.commit([cou1, cou2, cou3])

db.session.commit()

6-自关联一对多模型

6.1 理解

在一张表内表示一对多的关系
比如:评论内容,一条主评论可以有多个子评论,一个子评论只有一个主评论

6.2 代码实现

class Commet(db.Model):
    """评论"""
    __tablename__ = "comments"
    id = db.Column(db.Integer, primary_key=True)
    # 评论内容
    content = db.Column(db.Text, nullable = False)
    # 父评论id
    parent_id = db.Column(db.Integer, db.ForeignKey("comments.id"))
    # 父评论(也是评论模型)
    parent = db.relationship("Comment", remote_side=[id],backref=db.backref('childs',lazy='dynamic'))
    
if __name__ == "__main__":
    db.drop_all()
    db.create_all()
    
    com1 = Comment(content="我是主评论1")
    com11 = Comment(content="我是主评论1的子评论")
    com11.parent = com1
    
    com2 = Comment(content="我是主评论2")
    com21 = Comment(content="我是主评论2的子评论")
    com21.parent = com2

    db.session.add_all([])
    commit()

7-自关联多对多模型

7.1 理解

用户相互关注,同样是用户表,一个用户可以分别关注不同的用户同时也可以被不同的用户所关注

7.2 代码实现

# 用户关注其他用户(用户表,中间表)
# 创建中间表
tb_user_follows = db.Table(
    "tb_user_follows",
    db.Column("follower_id", db.Integer, db.ForeignKey('info_user.id'), primary_key = True),# 粉丝表
    db.Column("followed_id", db.Integer, db.ForeignKey('info_user.id'), primary_key = True)# 被关注表
)

class User(db.Model):
    __tablename__ = "info_user"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    # 用户所有的粉丝,添加了反向引用followed,代表用户关注了哪些人
    followers = db.relationship("User", secondary="tb_user_follows",primaryjoin=id==tb_user_follows.c.followed_id),
    secondaryjoin=id==tb_user_follows.c.follower_id,backref=db.backref("followed",lazy="dynamic"),

8-数据库迁移

数据库迁移
目的:当数据库的表结构发生变化之后,如果直接删除原有的数据,在添加新的数据,可能导致数据丢失,需要使用数据迁移
注意点:数据库的迁移是为了备份表结构,而不是数据
想要备份数据,需要使用工具,navicat

数据库迁移,操作步骤:
安装扩展:
flask-script
flask_migrate

from flask-script import Manager
from flask-migrate import Migrate, MigrateCommand

创建manager对象,管理app
manager = Manager(app)

Migrate(app, db)

manager.add_command('db', MigrateCommand)

相关迁移命令

生成迁移文件夹,管理迁移脚本
python xxx.py db init

将模型类生成迁移脚本
python xxx.py db migrate -m '注释'

将迁移脚本更新到数据库中
python xxx.py db upgrade

更新的过程数据一般不会丢失

降级操作
python xxx.py db downgrade

查看最新的版本号
python xxx.py db show 

查看当前版本
python xxx.py db current

查看所有历史版版本

python xxx.py db history

升级操作与降级操作单位都是一个版本,如果想从最低版本更新到最新版本
python xxx.py db upgrade 版本号  这条命令可以将数据库升级到指定版本

数据库降级过程中导致数据丢失,升级一般不会导致数据丢失

写在最后的杂七杂八

#为了方便数据库的关联查询
#不会在数据库中产生实体字段
#如果知道了角色的情况下,能否快速查询出那些用户扮演该角色
#原始查询方法:
role = Role.query.get(1)
user = User.query.filter(User.role_id == role.id).all()
#快速查询方式:
#关系属性,在一方添加关系属性:
#“一方属性名” = db.relationship("多方模型类")
#获取一个用户,快速查询这个用户的角色
#原始查询方法
user = User.query.get(1)
role = Role.query.get(user.role_id).first()
#快速查询:
#backref 添加反向属性,可以快速查询
users = db.relationship("多方模型类", backref='role')
users.role
#lazy属性:解决relationship 性能与效率问题
#一旦使用了relationship,backref 自动做子查询
#子查询:查询出一方,自动关联查询多方
#lazy使用
users = relationship("多方模型类", backref="", lazy="dynamic")
#动态查询,只有用到了才去查询


————————————————
版权声明:本文为CSDN博主「kobe_OKOK_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/kobe_okok/article/details/119978755

猜你喜欢

转载自blog.csdn.net/liuqinhou/article/details/132117571