flask拓展(数据库操作)
目录
一、初始Flask数据库操作1.Flask模型Flask默认并没有提供任何数据库操作的API 我们可以选择任何适合自己项目的数据库来使用 Flask中可以自己的选择数据,用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine) SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的低层功能。 ORM: 将对对象的操作转换为原生SQL 优点 易用性,可以有效减少重复SQL 性能损耗少 设计灵活,可以轻松实现复杂查询 移植性好 针对于Flask的支持,官网地址 pip install flask-sqlalchemy 安装驱动 pip install pymysql 2. 定义模型使用SQLALchemy的对象去创建字段 其中__tablename__指定创建的数据库的名称 创建models.py文件,其中定义模型 from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Student(db.Model): s_id = db.Column(db.Integer,primary_key=True,autoincrement=True) s_name = db.Column(db.String(16),unique=True) s_age = db.Column(db.Integer,default=1) __tablename__ = "student" 其中: Integer表示创建的s_id字段的类型为整形, primary_key表示是否为主键 String表示该字段为字符串 unique表示该字段唯一 default表示默认值 autoincrement表示是否自增 3. 创建数据表在视图函数中我们引入models.py中定义的db from App.models import db @blue.route("/createdb/") def create_db(): db.create_all() return "创建成功" @blue.route('/dropdb/') def drop_db(): db.drop_all() return '删除成功' 其中: db.create_all()表示创建定义模型中对应到数据库中的表 db.drop_all()表示删除数据库中的所有的表 4. 初始化SQLALchemy在定义的__init__.py文件中使用SQLALchemy去整合一个或多个Flask的应用 有两种方式: 第一种: from flask_sqlalchemy import SQLALchemy app = Flask(__name__) db = SQLAlchemy(app) 第二种: from App.models import db def create_app(): app = Flask(__name__) db.init_app(app) return app 5. 配置数据库的访问地址官网配置参数 数据库连接的格式: dialect+driver://username:[email?protected]:port/database dialect数据库实现 driver数据库的驱动 例子: 设置如下: "mysql+pymysql://root:[email?protected]:3306/HelloFlask" 在初始化__init__.py文件中如下配置: app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:[email?protected]:3306/HelloFlask" 6. 对学生数据进行CRUD操作语法: 类名.query.xxx 获取查询集: all() filter(类名.属性名==xxx) filter_by(属性名=xxx) 数据操作: 在事务中处理,数据插入 db.session.add(object) db.session.add_all(list[object]) db.session.delete(object) db.session.commit() 修改和删除基于查询 6.1 想学生表中添加数据@blue.route('/createstu/') def create_stu(): s = Student() s.s_name = '小花%d' % random.randrange(100) s.s_age = '%d' % random.randrange(30) db.session.add(s) db.session.commit() return '添加成功' 提交事务,使用commit提交我们的添加数据的操作 6.2 获取所有学生信息将学生的全部信息获取到,并且返回给页面,在页面中使用for循环去解析即可 @blue.route("/getstudents/") def get_students(): students = Student.query.all() return render_template("StudentList.html",students=students) 6.3 获取s_id=1的学生的信息写法1: students = Student.query.filter(Student.s_id==1) 写法2: students = Student.query.filter_by(s_id=2) 注意:filter中可以接多个过滤条件 写法3: sql = 'select * from student where s_id=1' students = db.session.execute(sql) 6.4 修改学生的信息写法1: students = Student.query.filter_by(s_id=3).first() students.s_name = '哈哈' db.session.commit() 写法2: Student.query.filter_by(s_id=3).update({'s_name':'娃哈哈'}) db.session.commit() 6.5 删除一个学生的信息写法1: students = Student.query.filter_by(s_id=2).first() db.session.delete(students) db.session.commit() 写法2: students = Student.query.filter_by(s_id=1).all() db.session.delete(students[0]) db.session.commit() 注意:filter_by后的结果是一个list的结果集 重点注意:在增删改中如果不commit的话,数据库中的数据并不会更新,只会修改本地缓存中的数据,所以一定需要db.session.commit() 二、深入Flask数据库操作1. 深入数据库增删改查定义模型,并定义初始化的函数: class Student(db.Model): s_id = db.Column(db.Integer,default=1) __tablename__ = "student" def __init__(self,name,age): self.s_name = name self.s_age = age 1.1 增--批量增加第一种方式: @blue.route('/createstus/') def create_users(): stus = [] for i in range(5): # 实例化Student的对象 s = Student() # 对象的属性赋值 s.s_name = '张三%s' % random.randrange(10000) s.s_age = '%d' % random.randrange(100) stus.append(s) # 添加需要创建的数据 db.session.add_all(stus) # 提交事务到数据库 db.session.commit() return '创建成功' 注:在创建单条数据的时候使用db.session.add(),在创建多条数据的时候使用db.session.add_all() 第二种方式: @blue.route('/createstus/') def create_users(): stus = [] for i in range(5): # 使用类的初始化去创建Student对象 s = Student('张三%s' % random.randrange(10000),'%d' % random.randrange(100)) stus.append(s) db.session.add_all(stus) db.session.commit() return '创建成功' 1.2 查--使用运算符获取查询集 filter(类名.属性名.运算符(‘xxx’)) filter(类名.属性 数学运算符 值) 运算符: contains: 包含 startswith:以什么开始 endswith:以什么结束 in_:在范围内 like:模糊 __gt__: 大于 __ge__:大于等于 __lt__:小于 __le__:小于等于 筛选: offset() limit() order_by() get() first() paginate() 逻辑运算: 与 and_ filter(and_(条件),条件…) 或 or_ filter(or_(条件),条件…) 非 not_ filter(not_(条件),条件…) 例子1:
例子2: 跳过offset几个信息,截取limit结果的几个值 # 按照id降序排列 stus = Student.query.order_by('-s_id') # 按照id升序排列 stus = Student.query.order_by('s_id') stus = Student.query.order_by(asc('s_id')) stus = Student.query.order_by('s_id asc') # 按照id降序获取三个 stus = Student.query.order_by('-s_id').limit(3) stus = Student.query.order_by('s_id desc').limit(3) from sqlalchemy import desc stus = Student.query.order_by(desc('s_id')).limit(3) # 获取年龄最大的一个 stus = Student.query.order_by('-s_age').first() # 跳过3个数据,查询5个信息 stus = Student.query.order_by('-s_age').offset(3).limit(5) # 跳过3个数据 stus = Student.query.order_by('-s_age').offset(3) # 获取id等于24的学生 stus = Student.query.filter(Student.s_id==24) stus = Student.query.get(24) 例子3:
例子4: 分页: 后端数据处理: # 方法一:手动实现分页,使用offset和limit page = int(request.args.get('page',1)) stus = Student.query.offset((page-1)*5).limit(5) # 方法二: 使用切片[:] s_page = (page - 1)*5 e_page = page * 5 stus = Student.query.all()[s_page: e_page] # 方法三:使用paginate # 查询第几页的数据 page = int(request.args.get('page',1)) # 每一页的条数多少,默认为10条 per_page = int(request.args.get('per_page',10)) # 查询当前第几个的多少条数据 paginate = Student.query.order_by('-s_id').paginate(page,per_page,error_out=False) stus = paginate.items 前端数据展示: <h2>学生信息</h2> {% for stu in stus %} id:{{ stu.s_id }} 姓名:{{ stu.s_name }} 年龄:{{ stu.s_age }} <br> {% endfor %} <br> 总页数: {{ paginate.pages }} <br> 一共{{ paginate.total }}条数据 <br> 当前页数:{{ paginate.page }} <br> {% if paginate.has_prev %} <a href="/stupage/?page={{ paginate.prev_num }}">上一页</a>:{{ paginate.prev_num }} {% endif %} {% if paginate.has_next %} <a href="/stupage/?page={{ paginate.next_num }}">下一页</a>:{{ paginate.next_num }} {% endif %} <br> <br> 页码:{% for i in paginate.iter_pages() %} <a href="/stupage/?page={{ i }}">{{ i }}</a> {% endfor %} 2. 关联关系2.1 一对多建立模型学生模型: class Student(db.Model): s_id = db.Column(db.Integer,autoincrement=True) s_name = db.Column(db.String(20),default=18) s_g = db.Column(db.Integer,db.ForeignKey('grade.g_id'),nullable=True) __tablename__ = 'student' 班级模型: class Grade(db.Model): g_id = db.Column(db.Integer,autoincrement=True) g_name = db.Column(db.String(10),unique=True) g_desc = db.Column(db.String(100),nullable=True) g_time = db.Column(db.Date,default=datetime.now) students = db.relationship('Student',backref='stu',lazy=True) __tablename__ = 'grade' 官网解释有如下几个lazy的参数: lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据:,有如下四个值: select/True: (which is the default) means that SQLAlchemy will load the data as necessary in one go using a standard select statement. joined/False: tells SQLAlchemy to load the relationship in the same query as the parent using a JOIN statement. subquery: works like ‘joined’ but instead SQLAlchemy will use a subquery. dynamic: is special and useful if you have many items. Instead of loading the items SQLAlchemy will return another query object which select就是访问到属性的时候,就会全部加载该属性的数据。 joined则是在对关联的两个表进行join操作,从而获取到所有相关的对象。 dynamic则不一样,在访问属性的时候,并没有在内存中加载数据,而是返回一个query对象,需要执行相应方法才可以获取对象, 注意: 当在Student模型中新增s_g字段后,在执行db.create_all()方法时,该Student模型映射到数据库中的表并不会新增s_g字段,因此字段的新增需要手动的执行SQL语句,并指定和Grade模型对应的表grade之间的主外键关系。 alter table student add s_g int; ALTER TABLE student add FOREIGN KEY (s_g) references grade(g_id); 2.2
注意:表的外键由db.ForeignKey指定,传入的参数是表的字段。db.relations它声明的属性不作为表字段,第一个参数是关联类的名字,backref是一个反向身份的代理,相当于在Student类中添加了stu的属性。例如,有Grade实例dept和Student实例stu。dept.students.count()将会返回学院学生人数;stu.stu.first()将会返回学生的学院信息的Grade类实例。一般来讲db.relationship()会放在一这一边。 3. 数据库迁移在django中继承了makemigrations,可以通过migrate操作去更新数据库,修改我们定义的models,然后在将模型映射到数据库中。 在flask中也有migrate操作,它能跟踪模型的变化,并将变化映射到数据库中 2.1 安装migratepip install flask-migrate 2.2 配置使用migrate2.2.1 初始化,使用app和db进行migrate对象的初始化from flask_migrate import Migrate #绑定app和数据库 Migrate(app=app,db=db) 2.2.2 安装了flask-script的话,可以在Manager()对象上添加迁移指令from flask_migrate import Migrate,MigrateCommand app = Flask(__name__) manage = Manager(app=app) manage.add_command('db',MigrateCommand) 操作: python manage.py db init 初始化出migrations的文件,只调用一次 python manage.py db migrate 生成迁移文件 python manage.py db upgrade 执行迁移文件中的升级 python manage.py db downgrade 执行迁移文件中的降级 python manage.py db --help 帮助文档 三、补充Flask数据库多对多关系操作1. 关联关系---多对多定义模型: 引入SQLALchemy from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() 创建中间表 sc = db.Table('sc',db.Column('s_id',db.Integer,db.ForeignKey('student.s_id'),primary_key=True),db.Column('c_id',db.ForeignKey('courses.c_id'),primary_key=True) ) 创建学生类Student class Student(db.Model): s_id = db.Column(db.Integer,nullable=True) __tablename__ = 'student' def __init__(self,age): self.s_name = name self.s_age = age self.s_g = None 创建课程表的模型,Course类 class Course(db.Model): c_id = db.Column(db.Integer,autoincrement=True) c_name = db.Column(db.String(20),unique=True) students = db.relationship('Student',secondary=sc,backref='cou') __tablename__ = 'courses' def __init__(self,name): self.c_name = name sc表由db.Table声明,我们不需要关心这张表,因为这张表将会由SQLAlchemy接管,它唯一的作用是作为students表和courses表关联表,所以必须在db.relationship()中指出sencondary关联表参数。lazy是指查询时的惰性求值的方式,这里有详细的参数说明,而db.backref是声明反向身份代理,其中的lazy参数是指明反向查询的惰性求值方式. 2. 添加学生和课程之间的关系通过页面中传递学生的id和课程的id,分别获取学生的对象和课程的对象,在使用关联关系append去添加学生对象,并且add以后再commit后,就可以在中间表sc中查看到新增的关联关系了。 userid = request.form.get('userid') courseid = request.form.get('courseid') stu = Student.query.get(userid) cou = Course.query.get(courseid) cou.students.append(stu) db.session.add(cou) db.session.commit() 3. 删除学生和课程之间的关系通过页面获取传递的学生的id和课程的id,分别获取学生对象和课程对象,在使用关联关系remove去删除学生对象,并commit将事务提交到数据库中 stu = Student.query.get(s_id) cou = Course.query.get(c_id) cou.students.remove(stu) db.session.commit() 4. 通过课程查询学生的信息以下定义在课程course的模型中,所以通过课程查询学生的信息,语法为课程的对象.studengs。如果知道学生的信息反过来找课程的信息,则使用backref的反向关联去查询,语语法为学生的对象.cou(反向) students = db.relationship(‘Student‘,backref=‘cou‘) cou = Course.query.get(2) stus = cou.students 5. 通过学生去查询课程的信息stu = Student.query.get(id) cous = stu.cou (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |