<Flask>-sqlalchemy operation database

<Flask>-sqlalchemy operation database_db.drop_all()_kobe_OKOK_'s blog-CSDN Blog

1 Brief introduction

Operational data is divided into database model creation and database migration, and database creation depends on flask-sqlalchemy

  1. one-to-many model
  2. many-to-many model
  3. Self-associated one-to-many model
  4. Self-Associated Many-to-Many Model


2- Import package and configuration

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-Add, delete, modify and check

3.1 increase

# 导包
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 delete

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

3.3 change

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

3.4 Check

    """ 插入测试数据
    # 删除表
    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 One-to-many model

4.1 Understanding

        There are many one-to-many cases in life, for example: people and mobile phones, one person can have multiple mobile phones, a person is one party, and a mobile phone is many parties, a role can have multiple users, and each user has only one Role. When you need to query which users belong to a certain role, you can write code like this:

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

        Similarly, when you know a user and want to know what role the user plays, you can write code like this:

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

        Although it is possible to write code in this way, it is relatively troublesome. Next, we can better realize the "one-to-many relationship model" by adding relationship attributes to "one party".

4.2 Code implementation

# 一方(关系属性写在一方)
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 Many-to-many model

5.1 Understanding

Students choose courses online,
teachers and classes,
users and news collection relationship Between many-to-many, a separate table needs to be used to record
the relationship between the two tables.
Multiple
The two single tables correspond to one party, and the intermediate table is multi-party,
so two foreign keys should be written in the intermediate table, and the relationship attributes can be written in either party

5.2 Code implementation

# 创建中间表
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- Self-Association One-to-Many Model

6.1 Understanding

Represent a one-to-many relationship in a table
For example: comment content, a main comment can have multiple sub-comments, and a sub-comment has only one main comment

6.2 Code implementation

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- Self-Association Many-to-Many Model

7.1 Understanding

Users follow each other. It is also a user table. A user can follow different users and be followed by different users.

7.2 Code implementation

# 用户关注其他用户(用户表,中间表)
# 创建中间表
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-Database Migration

数据库迁移
目的:当数据库的表结构发生变化之后,如果直接删除原有的数据,在添加新的数据,可能导致数据丢失,需要使用数据迁移
注意点:数据库的迁移是为了备份表结构,而不是数据
想要备份数据,需要使用工具,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 版本号  这条命令可以将数据库升级到指定版本

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

Miscellaneous written at the end

#为了方便数据库的关联查询
#不会在数据库中产生实体字段
#如果知道了角色的情况下,能否快速查询出那些用户扮演该角色
#原始查询方法:
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")
#动态查询,只有用到了才去查询


————————————————
Copyright statement: This article is an original article of CSDN blogger "kobe_OKOK_", following the CC 4.0 BY-SA copyright agreement, please attach the original source link and this statement for reprinting .
Original link: https://blog.csdn.net/kobe_okok/article/details/119978755

Guess you like

Origin blog.csdn.net/liuqinhou/article/details/132117571