1、使用paginate实现分页:
- 基础指令(新建对象)
- 基础指令(使用对象属性)
2、几种类型的表操作:
- 一对一:例如一个人只能有一张身份证。
- 一对多:例如班级和学生(一个班级可以对应多个学生,而每个学生只能有一个班级,对于学生而言这就是一对一的关系)
- 多对多:例如一个学生可以选择多门选修课,一门选修课对应多个学生(多对多关系需要有一个中间表,多对多关系可以分解为两个一对多关系)
3、一对多操作:
- 现在通过一对多的关系(一个班级可以有多个学生)在数据库建表,进行说明:
- 项目模板借鉴:Python轻量级Web框架Flask(6)中的项目模板
3.1、代码展示:
__init __代码:
# __init__.py : 初始化文件,创建Flask应用
from flask import Flask
from .views import blue
from .exts import init_exts
def creat_app():
app = Flask(__name__)
# 注册蓝图
app.register_blueprint(blueprint=blue)
# 配置数据库
# db_uri = 'sqlite:///sqlite3.db'
db_uri = 'mysql+pymysql://root:123456@localhost:3306/flaskdb2' # mysql的配置,要记得在mySQL中配置flaskdb2数据库
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
# 建立一对多的多表关系:班级和学生(1:N)
# 班级表:
class Grade(db.Model):
__tablename__ = 'grade' # 表名
# 定义表字段
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True, index=True)
# 建立关联:
# 第一个参数:关联的模型名(表名)
# 第二个参数:反向引用的名称,grade对象
# 让student反过来得到grade对象的名称:student.grade
# 第三个参数:懒加载(不用的时候不调用,用到之后才调用)
# 注意:这里的students不是字段,是类属性
students = db.relationship('Student', backref='grade', lazy=True) # 这里Student因为在之后定义,所以可以先用字符串来替代
# 学生表:
class Student(db.Model):
__tablename__ = 'student'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True)
age = db.Column(db.Integer)
# 外键:跟Grade表中的id字段关联
gradeid = db.Column(db.Integer, db.ForeignKey(Grade.id))
完成了上面的步骤之后,下一步就是经典的数据迁移步骤:
1、在pycharm终端中把整个项目文件拖进去,然后在终端执行:flask db init
2、在终端继续执行:flask db migrate
3、在终端继续执行:flask db upgrade
上述步骤执行结束之后,models中的表就已经生成了,但是其中还没有添加数据,此阶段项目概览如下。
3.2、项目概览:
3.3、多表操作:
多表操作主要是在views.py文件中操作
# 在views.py中放路由和视图函数
import random
from flask import Blueprint, request, render_template
from .models import * #后面是用views来控制数据库的,所以要在views中导入models文件
# 蓝图
blue = Blueprint('user', __name__)
@blue.route('/')
def index():
return 'index'
# 一对多添加数据:先给唯一项添加数据,然后再给多项添加数据,因为外键绑定在多项上
@blue.route('/add_grade/')
def add_grade():
# 添加班级
grades = []
for i in range(5):
grade = Grade()
grade.name = f'HuaQing{i}班'
grades.append(grade)
try:
db.session.add_all(grades)
db.session.commit()
except Exception as e:
print(f'e:{e}')
db.session.rollback()
db.session.flush()
return 'add_Ok!'
@blue.route('/add_stu/')
def add_stu():
l = ['张', '刘', '王', '赵']
# 添加学生
stus = []
for i in range(11):
stu = Student()
stu.name = str(l[random.randint(0, 3)]) + str(i)
stu.age = random.randint(18,21)
stu.gradeid = random.randint(1,2)
stus.append(stu)
print(stus)
try:
db.session.add_all(stus)
db.session.commit()
except Exception as e:
print(f'e:{e}')
db.session.rollback()
db.session.flush()
return 'add_Ok!'
# 修改:注意修改之前要先查找数据
@blue.route('/updatestu/')
def upset_stu():
stu = Student.query.first()
stu.name = '改名六六六'
try:
db.session.commit()
except Exception as e:
print('e:', e)
db.session.rollback()
db.session.flush()
return 'XiuGaiOk!'
# 删除:注意删除之前要先查找数据
@blue.route('/del_stu/')
def delete_stu():
stu = Student.query.first()
db.session.delete(stu)
try:
db.session.commit()
except Exception as e:
print('e:', e)
db.session.rollback()
db.session.flush()
return 'ShanChuOk!'
# 查询:因为在models中有设置,所以这里可以反向引用
@blue.route('/get/')
def get():
# 查询id为40的学生所在的班级
stu = Student.query.get(40)
print(stu.name, stu.age)
print(stu.gradeid, stu.grade, stu.grade.name,
stu.grade.id)
# 查询gradeid是2的所有学生
grade = Grade.query.get(2)
print(grade.name,
grade.students) # 这里的students在models中的Grade中最后定义的
return 'getstuOK!'
4、多对多操作:
-
多对多继续用上面一对多的项目框架
-
设计多对多数据表:设计一个用户和电影之间多对多的表,中间表设计为收藏表(一个用户可以收藏多个电影,一个电影也可以被多个用户收藏),表格关系如下:
-
什么是正向引用,什么是反向引用:A表和B表关联,A调用B,对于A来说是正向引用,对于B来说是反向引用。
-
多对多中表格的建立可以通过下述的标准代码方法进行,也可以设置两个一对多来实现。
4.1、举例实现多对多操作:
1、 models中的代码:
# models.py : 模型,数据库
from .exts import db
# ---------------------------------多对多---------------------------------
# 中间表(收藏表):注意在多对多关系中中间表要写在其他表的最前面,而且表格写法也和普通表不一样。
# 中间表中可以不用单独设置主键,这样就可以把关联的两个表的主键作为主键,在数据库中如果有两个主键,则这两个主键的组合代表了一行数据。
collect = db.Table( # db中的还有一个Table的类,用它可以创建一个Table对象
'collects',# 表名
# 注意,下面代码中'usermodel.id'中usermodel是UserModel的小写表示,由于类的特性(没法调用写在后面的类),在模型中可以先用字符串表示。
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
db.Column('movie_id', db.Integer, db.ForeignKey('movie.id'), primary_key=True),
)
# 普通表(用户表):
class User(db.Model):
__tablename__ = 'users' # 表名
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30))
age = db.Column(db.Integer)
# 普通表(电影表):
class Movie(db.Model):
__tablename__ = 'movies' # 表名
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30))
# 关联:这个关联可以建立在电影表中,也可以建立在用户表中,但是参数就有所不同了。
# secondary=collect:设置中间表
movie_users = db.relationship('UserModel', backref='user_movies', lazy=True, Secondary=collect)
'''
lazy属性:
懒加载,可以延迟在使用关联属性的时候才建立关联
lazy='dynamic':会返回一个query对象(查询集),可以继续使用其他查询方法,如all()
lazy='select':首次访问到属性的时候,就会全部加载该属性的数据
lazy='joined':在对关联的两个表进行join操作,从而获取所有相关的对象
lazy='True':返回一个可用的列表对象,同select
'''
2、数据迁移:因为在一对多中已经数据迁移过了,所以就不用初始化了
在终端中该项目路径下执行:flask db migrate 此时会在migrations中的versions中出现一个新编号的py文件
在终端中该项目路径下执行:flask db upgrade 此时会在数据库中生成这三个表
3、多对多表格操作:这部分主要在views文件中完成
# 在views.py中放路由和视图函数
import random
from flask import Blueprint, request, render_template
from .models import * #后面是用views来控制数据库的,所以要在views中导入models文件
# 蓝图
blue = Blueprint('user', __name__)
@blue.route('/')
def index():
return 'index'
# ---------------------------------多对多---------------------------------
# 添加数据
@blue.route('/add_user/')
def add_users():
l = ['张', '刘', '王', '赵']
# 添加用户
users = []
for i in range(1, 6):
user = User()
user.name = str(l[random.randint(0, 3)]) + str(i)
user.age = random.randint(8,100)
users.append(user)
try:
db.session.add_all(users)
db.session.commit()
except Exception as e:
print(f'e:{e}')
db.session.rollback()
db.session.flush()
return 'add_Ok!'
@blue.route('/add_movie/')
def add_movies():
l = ['流浪地球', '阿凡达', '蜡笔', '拉丁哇']
# 添加电影
movies = []
for i in range(1, 6):
movie = Movie()
movie.name = str(l[random.randint(0, 3)]) + str(i)
movies.append(movie)
try:
db.session.add_all(movies)
db.session.commit()
except Exception as e:
print(f'e:{e}')
db.session.rollback()
db.session.flush()
return 'add_Ok!'
@blue.route('/add_collect/')
def add_collects():
# 用户收藏电影
user = User.query.get(1)
movie = Movie.query.get(1)
user.user_movies.append(movie)
db.session.commit()
return 'add_Ok!'
# 查询
@blue.route('/get_collect/')
def get_collect():
# 查找某个用户收藏的所有电影
user = User.query.get(1)
print(user.user_movies)
print(Movie.query.get(5).movie_users)
return 'query_OK!'
# 修改操作和单表操作一样
# 删除:
@blue.route('/del_user/')
def del_users():
user = User.query.get(1)
# 删除了user中的id=1,则在collect表中和1相关的数据也都会被删除
# 删除操作只会影响关联表,不会影响其他表
db.session.delete(user)
db.session.commit()
return 'OK!'
总结:
- 1、不论是单表操作还是多表操作流程都一样:
- 首先在models中建表。(在一对多的情况下,外键是写在多的表格中)
- 然后在终端进行“数据迁移”(就是把flask模型中建的表放到电脑的数据库中),这一步就要看你__init __中db_uri连接的是什么数据库了。
- 数据迁移要注意有过初始化的就不用重复初始化。
- 数据表的:增、删、改、查都是在views中进行的,要注意的一点是一对多和多对多中数据增加是有区别的,多对多中,对中间表进行添加数据时和普通表添加数据有区别。