Flask (三) 数据迁移

数据迁移

安装
    pip install flask-migrate
初始化
    使用appdb进行migrate对象初始化
        from flask_migrate import Migrate
        migrate = Migrate()
        migrate.init_app(app=app, db=db)
    
    安装了flask-script后,可以在manager上添加迁移指令
        from flask_migrate import MigrateCommand
        manager.add_command('db', MigrateCommand)
    
操作
    python manager.py db init  只调用一次, 这里的db是添加命令时给定的名称
    python manager.py db migrate  生成迁移文件
    python manager.py db upgrade  执行迁移中的升级
    python manager.py db downgrade  执行迁移中的降级
  

模型进阶

创建模型

# 模型:类
class Person(db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(20), unique=True)
    age = db.Column(db.Integer, default=1)
 
字段类型
类型名Python类型说 明
Integer int 普通整数,一般是 32 位
SmallInteger int 取值范围小的整数,一般是 16 位
BigInteger int 或 long 不限制精度的整数
Float float 浮点数
Numeric decimal.Decimal 定点数
String str 变长字符串
Text str 变长字符串,对较长或不限长度的字符串做了优化
Unicode unicode 变长 Unicode 字符串
UnicodeText unicode 变长 Unicode 字符串,对较长或不限长度的字符串做了优化
Boolean bool 布尔值
Date datetime.date 日期
Time datetime.time 时间
DateTime datetime.datetime 日期和时间
Interval datetime.timedelta 时间间隔
LargeBinary str 二进制文件
常用约束
选项名说 明
primary_key 如果设为 True ,这列就是表的主键
unique 如果设为 True ,这列不允许出现重复的值
index 如果设为 True ,为这列创建索引,提升查询效率
nullable 如果设为 True ,这列允许使用空值;如果设为 False ,这列不允许使用空值
default 为这列定义默认值

模型操作

单表操作

增加数据
    a. 一次增加一条数据:
        p = Person()    
        p.name = '小明'    
        p.age = 22
        try:
            db.session.add(p)
            db.session.commit()
        except:
            # 回滚
            db.session.rollback()
            db.session.flush()
    b. 一次添加多条数据
        persons = []
        for i in range(10,30):
            p = Person()
            p.name = '宝强' + str(i)
            p.age = i
            persons.append(p)
        db.session.add_all(persons)
        db.session.commit()
删除数据
    p = Person.query.first()  # 获取第一条数据
    db.session.delete(p)
    db.session.commit()
    
修改数据
    p = Person.query.first()
    p.age = 100
    db.session.commit()
        
查询数据
    过滤器
        filter()    把过滤器添加到原查询上,返回一个新查询
        filter_by() 把等值过滤器添加到原查询上,返回一个新查询
        limit()   使用指定的值限制原查询返回的结果数量,返回一个新查询
        offset()    偏移原查询返回的结果,返回一个新查询
        order_by()  根据指定条件对原查询结果进行排序,返回一个新查询
        group_by()  根据指定条件对原查询结果进行分组,返回一个新查询
    常用查询
        all()   以列表形式返回查询的所有结果
        first() 返回查询的第一个结果,如果没有结果,则返回 None
        first_or_404()  返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应
        get()   返回指定主键对应的行,如果没有对应的行,则返回 None
        get_or_404()    返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应
        count() 返回查询结果的数量
        paginate()  返回一个 Paginate 对象,它包含指定范围内的结果
        查询属性
            contains
            startswith
            endswith
            in_
            __gt__
            __ge__
            __lt__
            __le__
    逻辑运算
        and_
            filter(and_(条件),条件…)
        or_
            filter(or_(条件),条件…)
        not_
            filter(not_(条件),条件…)
    示例:   
        查询:
            persons = Person.query.all()  # 获取所有
            persons = Person.query.filter(Person.age>22)
            # filter功能比filter_by强大
            persons = Person.query.filter(Person.age==22)  # filter(类.属性==值)
            persons = Person.query.filter_by(age=22) # filter_by(属性=值)
            persons = Person.query.filter(Person.age.__lt__(22)) # <
            persons = Person.query.filter(Person.age.__le__(22)) # <=
            persons = Person.query.filter(Person.age.__gt__(22)) # >
            persons = Person.query.filter(Person.age.__ge__(22)) # >=
            persons = Person.query.filter(Person.age.startswith('宝'))  # 开头匹配
            persons = Person.query.filter(Person.age.endswith('宝'))  # 结尾匹配
            persons = Person.query.filter(Person.age.contains('宝'))  # 包含
            persons = Person.query.filter(Person.age.in_([11,12,22]))  # in_
            persons = Person.query.filter(Person.age>=20, Person.age<30)  # and_
            persons = Person.query.filter(and_(Person.age>=20, Person.age<30))  # and_
            persons = Person.query.filter(or_(Person.age>=30, Person.age<20))  # or_
            persons = Person.query.filter(not_(Person.age<30))  # not_
        
        排序:
            persons = Person.query.limit(5)  # 取前5个
            persons = Person.query.order_by('age')  # 升序
            persons = Person.query.order_by('-age')  # 降序
            persons = Person.query.order_by(desc('age'))  # 降序
            persons = Person.query.offset(5)  # 跳过前5个
        
        分页:
            # 获取页码page和每页数量num
            page = int(request.args.get('page'))
            num = int(request.args.get('num'))
            # 手动做分页
            persons = Person.query.offset((page-1) * num).limit(num)
            # 使用paginate做分页
            persons = Person.query.paginate(page, num, False).items
       
        paginate对象的属性:
            items:返回当前页的内容列表
            has_next:是否还有下一页
            has_prev:是否还有上一页
            next(error_out=False):返回下一页的Pagination对象
            prev(error_out=False):返回上一页的Pagination对象
            page:当前页的页码(从1开始)
            pages:总页数
            per_page:每页显示的数量
            prev_num:上一页页码数
            next_num:下一页页码数
            query:返回创建该Pagination对象的查询对象
            total:查询返回的记录总数
            
 

多表关联

一对多
# 一对多
class Grade(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(16))
    # 定义班级标的一对多关系,不是字段, Student为学生表模型, backref为反向查找名称
    students = db.relationship('Student', backref='grade1', lazy=True)
class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(16))
    age = db.Column(db.Integer, default=1)
    # 创建外键,关联到班级表的主键,实现一对多关系,班级表中也要有对应操作
    grade = db.Column(db.Integer, db.ForeignKey(Grade.id))
    查: 
        # 获取学生的所在班级信息(反向)
        stu = Student.query.get(stuid)
        grade = stu.stus
        
        # 获取班级的所有学生 (正向)
        grade = Grade.query.get(gradeid)
        students = grade.students
    删:
            # 删除班级后, 学生的grade字段会变为null
            grade = Grade.query.get(id)
            db.session.delete(grade)
            db.session.commit()
 
多对多
用户收藏电影,一个用户可以收藏多部电影, 一部电影可以被不同的用户收藏, 是一个多对多关系.
# 中间表(不是模型)
collects = db.Table('collects',
    # user_id为表字段名称, user.id为外键表的id
    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 Movie(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(200))
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(16))
    age = db.Column(db.Integer, default=1)
    # 多对多  关联的学生表格的模型, 中间表的名称, 反向查找
    movies = db.relationship('Movie',  backref='users', secondary=collects, lazy='dynamic')
    
    lazy属性:
        懒加载,可以延迟在使用关联属性的时候才建立关联
        lazy='dynamic': 会返回一个query对象(查询集),可以继续使用其他查询方法,如all().
        lazy='select': 首次访问到属性的时候,就会全部加载该属性的数据.
        lazy='joined': 在对关联的两个表进行join操作,从而获取到所有相关的对象
        lazy=True:  返回一个可用的列表对象,select
        
查:
    # 查询用户收藏的所有电影
     user = User.query.get(id)
     movies = user.movies
        
    # 查询电影被哪些用户收藏
     movie = Movie.query.get(id)
     users = movie.users
    
删:
    # 中间表的数据会被级联删除
     movie = Movie.query.get(id)
     db.session.delete(movie)
     db.session.commit()
     
    # 用户收藏电影
    user = User.query.get(id)
    movie = Movie.query.get(id)
    user.movies.append(movie)
    db.session.commit()
 
原文地址:https://www.cnblogs.com/gugubeng/p/9722720.html