Python轻量级Web框架Flask(7)—— 几种类型表操作介绍(单表操作、多表操作)

0、前言:

  • 这篇文章介绍多表操作,并在后面附了多表操作的项目

1、几种类型的表操作:

  • 一对一:例如一个人只能有一张身份证。
  • 一对多:例如班级和学生(一个班级可以对应多个学生,而每个学生只能有一个班级,对于学生而言这就是一对一的关系)
  • 多对多:例如一个学生可以选择多门选修课,一门选修课对应多个学生(多对多关系需要有一个中间表,多对多关系可以分解为两个一对多关系,中间表和其他表的关系都是多对1)

1.1、一对多操作:

  • 通过下面的多对多关系示例,作为一对多关系介绍的模板(具体代码实现和下面表有所出入,不影响理解)
    在这里插入图片描述

1.2、多对多操作

  • 通过下面的多对多关系示例,作为多对多关系介绍的模板(具体代码实现和下面表有所出入,不影响理解)
    在这里插入图片描述

1.3、项目概览

  • 项目模板借鉴:Python轻量级Web框架Flask(6)中的项目模板
  • 项目中具体介绍了一对多表操作的:增、删、改、查
    在这里插入图片描述

1.4、一对多与多对多关系的代码实现:

__init __代码:(用于初始化)

# __init__.py : 初始化文件,创建Flask应用
from flask import Flask
from .views import blue
from .exts import init_exts

def creat_app():
    app = Flask(__name__)

    # 注册蓝图(将views中的蓝图和对应app绑定,可能会存在有多个app的情况)
    # 蓝图就是为了便于模块化管理和拓展应用,蓝图会给每个url加上前缀
    app.register_blueprint(blueprint=blue)

    # 配置数据库(配置不同数据库软件,就要用不同配置,配置的目的,就是在用到数据库的时候让项目知道找什么数据库,去哪找数据库)
    # db_uri = 'sqlite:///sqlite3.db'
    db_uri = 'mysql+pymysql://root:123456@localhost:3306/more_table' # mysql的配置
    app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # 禁止对象追踪修改(为了不浪费服务器资源进行的设置)

    # 初始化插件
    init_exts(app=app)

    return app

exts代码:(用于安装插件)

from flask_sqlalchemy import SQLAlchemy # orm技术
from flask_migrate import Migrate # 数据迁移技术

db = SQLAlchemy()
migrate = Migrate()

def init_exts(app):
    db.init_app(app=app)
    migrate.init_app(app=app, db=db)

models 代码(用于构建)

# models.py : 模型,数据库

from .exts import db # 导入db对象就能通过python实现ORM技术,避免了写SQL语句。

# --------------------------------------------------------------
# 《一对多》
# 创建一对多关系表中的班级表
# 必须继承 db.Model User才能从普通的类变成模型
class Class_group(db.Model):
    # 表名
    __tablename__ = 'class_group'   # 数据迁移就是让模型变成表,ORM就是让类变成模型
    # 定义表字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(30), unique=True)
    # 在班级表中与学生表建立关联,便于让学生表反过来查询班级表,backref就是学生表反过来查班级表时调用的属性名
    students = db.relationship("Students", backref='gd', lazy=True)

# 创建一对多关系表中的学生表
class Students(db.Model):
    # 表名
    __tablename__ = 'student'   # 数据迁移就是让模型变成表,ORM就是让类变成模型
    # 定义表字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(30), unique=True)
    age = db.Column(db.Integer)
    # 外键
    class_group_id = db.Column(db.Integer, db.ForeignKey(Class_group.id))
# --------------------------------------------------------------
# 《多对多》
# 中间表(用新的方式建表),其实用之前的方式建立一个Collect(db.Model)然后设置两个外键也是可以的
collect = db.Table(
    'collect', # 表名称
    # 因为写在前面,所以写外键的时候,里面参数用字符串,注意外键中写的应该是下面建好的表名而不是类名
    # 将两个外键都设置为主键,这样只有在两个外键都符合的情况下才能找到数据
    db.Column('userid', db.Integer, db.ForeignKey('user.id'), primary_key=True),
    db.Column('movieid', db.Integer, db.ForeignKey('movie.id'), primary_key=True)
)

# 用户表
class UserModel(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(30))
    age = db.Column(db.Integer)

    # 因为是“用户表”和“电影表”多对多,所以要在这两个表中加一个关联代码(反向引用),这个代码加在用户表或者电影表中都可以,只是参数不同。
    # 关联代码中,backref是通过MovieModel调用与其相关所有UserModel当中的数据时使用的属性名。
    # lazy是允许懒加载,用到了加载,lazy设置为‘dynamic’返回的就是可以可以继续查询的查询集(建议使用dynamic)
    # secondary作用是表明中间表是哪个表
    movies = db.relationship('MovieModel', backref='users', lazy='dynamic', secondary=collect)

# 电影表
class MovieModel(db.Model):
    __tablename__ = 'movie'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(30))

views.py

# 在views.py中放路由和视图函数
import random

from flask import Blueprint, render_template, request
from .models import * #后面是用views来控制数据库的,所以要在views中导入models文件

# 蓝图(蓝图可以有多个,方便对路径进行区分)
blue = Blueprint('user', __name__)

@blue.route('/')
def index():
    return '这是Flask多表操作项目'
# ----------------------------------------
# 多表操作:1对多
# 增加班级数据
@blue.route('/add_class/')
def add_class():
    # 添加多条数据是通过列表实现的,就是将多个对象放到列表当中,将列表提交给数据库
    groups = []
    for i in range(10):
        group = Class_group()
        group.name = f'YiFu{i}class'
        groups.append(group)
    try:
        db.session.add_all(groups)
        db.session.commit()
    except Exception as e:
        print("Error:",e)
        db.session.rollback()
        db.session.flush()
    return 'ok!'

# 增加学生数据
@blue.route('/add_student/')
def add_student():
    students = []
    for i in range(30):
        student = Students()
        student.name = f'S-{i}'
        student.age = random.randint(10,20)
        student.class_group_id = random.randint(1,10)
        students.append(student)
    try:
        db.session.add_all(students)
        db.session.commit()
    except Exception as e:
        print('e:', e)
        db.session.rollback()
        db.session.flush()
    return "ok!"

# 修改
@blue.route('/update/')
def update():
    # 修改的前提是查询
    # 在数据库中查找name为'S-1'的第一个学生,并将其名字修改
    student_to_update = Students.query.filter_by(name='S-1').all()[0]
    if student_to_update:
        # 如果找到了学生,则更新其name字段为're'
        student_to_update.name = 're-1'
        db.session.commit()  # 提交更改到数据库
        return 'Student name updated successfully!', 200
    else:
        # 如果没有找到学生,则返回错误消息
        return 'No student found with name "S-1"', 404

# 整体修改
@blue.route('/re_data')
def re_data():
    # 删除前查询修改
    result = Students.query.filter_by(age=19).update({'age':88}, synchronize_session=False)
    db.session.commit()
    return "OK"

# 删除
@blue.route('/del_data')
def del_data():
    stu = Students.query.first()
    db.session.delete(stu)
    db.session.commit()
    return 'del ok!'

# 查询
@blue.route('/query_data')
def query_data():
    stu1 = Students.query.get(2)
    print(f'get方法拿到的id是2的数据的name属性{stu1.name}') # get方法拿到的id是2的数据的name属性re-1
    print(f'get方法拿到的id是2的数据的反向引用{stu1.gd}{stu1.gd.name}') # get方法拿到的id是2的数据的反向引用<Class_group 3>、YiFu2class
    cl = Class_group.query.get(3)
    print(cl) # <Class_group 3>
    print(f'反向引用:查询某个班级所有学生{cl.students}') # 反向引用:查询某个班级所有学生[<Students 2>, <Students 26>]
    for i in cl.students:
        print(i.name,i.age)
    return 'query ok!'
# ----------------------------------------
# 多表操作:多对多

# 添加用户
@blue.route('/add_user/')
def add_user():
    users = []
    for i in range(5):
        user = UserModel()
        user.name = f'us{i+1}'
        user.age = random.randint(20,30)
        users.append(user)
    try:
        db.session.add_all(users)
        db.session.commit()
    except Exception as e:
        print('E:', e)
        db.session.rollback()
        db.session.flush()
    return '多表操作——用户表数据添加完成'

# 添加电影
@blue.route('/add_movie/')
def add_movie():
    movies = []
    for i in range(3):
        movie = MovieModel()
        movie.name = f'Mv{i+1}'
        movies.append(movie)
    try:
        db.session.add_all(movies)
        db.session.commit()
    except Exception as e:
        print('E:', e)
        db.session.rollback()
        db.session.flush()
    return '多表操作——电影表数据添加完成'

# 收藏表添加数据(用户1看了电影1和3,用户2看了2和3,用户3看了1,2,3)
@blue.route('/add_collect_user')
def add_collect_user():
    # 用户1
    u1 = [1,3]
    for i in u1:
        user = UserModel.query.get(1)
        movie = MovieModel.query.get(i)
        user.movies.append(movie)
        db.session.commit()
    # 用户2
    u2 = [2,3]
    for i in u2:
        user = UserModel.query.get(2)
        movie = MovieModel.query.get(i)
        user.movies.append(movie)
        db.session.commit()
    # 用户3
    u3 = [1,2,3]
    for i in u3:
        user = UserModel.query.get(3)
        movie = MovieModel.query.get(i)
        user.movies.append(movie)
        db.session.commit()
    return '通过用户表给中间表添加数据完成'

# 收藏表添加数据(电影1被4和5看了,电影3被5看了)
@blue.route('/add_collect_movie/')
def add_collect_movie():
    # 电影1
    m1 = [4,5]
    for i in m1:
        movie = MovieModel.query.get(1)
        user = UserModel.query.get(i)
        movie.users.append(user)
        db.session.commit()
    # 电影3
    movie = MovieModel.query.get(3)
    user = UserModel.query.get(5)
    movie.users.append(user)
    db.session.commit()
    return "通过电影表给中间表添加数据完成!"

# 查询操作
@blue.route('/get_collect1/<int:user_num>')
def get_collect1(user_num):
    # 查看某个用户看过多少电影
    user = UserModel.query.get(user_num)
    movies = user.movies # 正是因为model中创建表时加了反向引用,才能实现。
    for i in movies:
        print(f'用户{user.name}看过电影{i.name}')
    return '查询视图函数1运行结束!'

@blue.route('/get_collect2/<int:movie_num>')
def get_collect2(movie_num):
    # 查看某个用户看过多少电影
    movie = MovieModel.query.get(movie_num)
    users = movie.users # 正是因为model中创建表时加了反向引用,才能实现。
    for i in users:
        print(f'电影{movie.name}{i.name}看过')
    return '查询视图函数2运行结束!'

# 多表操作的修改与单表操作修改相同
# 删除(不管是删除用户还是电影,中间表相关数据会自动删除)
@blue.route('/data_del/<int:uid>')
def data_del(uid):
    user = UserModel.query.get(uid)
    db.session.delete(user)
    db.session.commit()
    return '删除视图函数执行完成!'

app.py

# Flask翻页项目
from App import creat_app

app = creat_app()
if __name__ == '__main__':
    app.run(debug=True)

在构建项目时,完成model数据表结构后,要记得数据迁移:
1、在pycharm终端中把整个项目文件拖进去,然后在终端执行:flask db init
2、在终端继续执行:flask db migrate
3、在终端继续执行:flask db upgrade
上述步骤执行结束之后,models中的表就已经生成了,但是其中还没有添加数据


总结:

  • 1、不论是单表操作还是多表操作流程都一样:
    • 首先在models中建表。(在一对多的情况下,外键是写在多的表格中)
    • 然后在终端进行“数据迁移”(就是把flask模型中建的表放到电脑的数据库中),这一步就要看你__init __中db_uri连接的是什么数据库了。
    • 数据迁移要注意有过初始化的就不用重复初始化。
    • 数据表的:增、删、改、查都是在views中进行的,要注意的一点是一对多和多对多中数据增加是有区别的,多对多中,对中间表进行添加数据时和普通表添加数据有区别。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值