• 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()
     
  • 相关阅读:
    Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (gbk_chinese_ci,COERCIBLE) for operation '=' 一个解决办法(转载)
    mysql limit用法
    preparedStatement一个小技巧
    两个简单的压力测试代码。
    cookie实现session机制
    java.util.properties用法
    数据库是否使用外键,及视图,索引,存储过程的一些说明(zz)
    某项目要调用现有的100多个DLL 二 最最简单原型的思考
    面试题:红绿灯
    一个简单的封装 .net的日志功能
  • 原文地址:https://www.cnblogs.com/gugubeng/p/9722720.html
Copyright © 2020-2023  润新知