python框架之Flask基础篇(二)-------- 数据库的操做

1.flask链接数据库的四步:

  1. 倒入第三方数据库扩展包:from flask_sqlalchemy import SQLAlchemy
  2. 配置config属性,链接数据库:

    app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@localhost/first_flask"
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = Falsepython

  3. 建立数据库first_flask
  4. 建立操做数据库对象:db = SQLAlchemy(app)

下面直接上代码解释:mysql

 

# -*- coding:utf-8 -*-
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # url的格式为:数据库的协议://用户名:密码@ip地址:端口号(默承认以不写)/数据库名
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@localhost/first_flask" # 动态追踪数据库的修改. 性能很差. 且将来版本中会移除. 目前只是为了解决控制台的提示才写的 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # 建立数据库的操做对象 db = SQLAlchemy(app) class Role(db.Model): __tablename__ = "roles" id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(16),unique=True) # 给Role类建立一个uses属性,关联users表。 # backref是反向的给User类建立一个role属性,关联roles表。这是flask特殊的属性。 users = db.relationship('User',backref="role") # 至关于__str__方法。 def __repr__(self): return "Role: %s %s" % (self.id,self.name) class User(db.Model): # 给表从新定义一个名称,默认名称是类名的小写,好比该类默认的表名是user。 __tablename__ = "users" id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(16),unique=True) email = db.Column(db.String(32),unique=True) password = db.Column(db.String(16)) # 建立一个外键,和django不同。flask须要指定具体的字段建立外键,不能根据类名建立外键 role_id = db.Column(db.Integer,db.ForeignKey("roles.id")) def __repr__(self): return "User: %s %s %s %s" % (self.id,self.name,self.password,self.role_id) @app.route('/') def hello_world(): return 'Hello World!'


if __name__ == '__main__': # 删除全部的表 db.drop_all() # 建立表 db.create_all() ro1 = Role(name = "admin") # 先将ro1对象添加到会话中,能够回滚。 db.session.add(ro1) ro2 = Role() ro2.name = 'user' db.session.add(ro2) # 最后插入完数据必定要提交 db.session.commit() us1 = User(name='wang', email='wang@163.com', password='123456', role_id=ro1.id) us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id) us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id) us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id) us5 = User(name='tang', email='tang@itheima.com', password='158104', role_id=ro2.id) us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id) us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id) us8 = User(name='liu', email='liu@itheima.com', password='867322', role_id=ro1.id) us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id) us10 = User(name='sun', email='sun@163.com', password='235523', role_id=ro2.id) db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10]) db.session.commit() app.run(debug=True)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------sql

下面插播一条bug:数据库

当把表格建立完成,注释这两句话:django

 # 删除全部的表 db.drop_all() # 建立表 db.create_all()

而后向表格里面插入数据,此时会出现这样的错误:flask

sqlalchemy.exc.IntegrityError: (_mysql_exceptions.IntegrityError) (1062, "Duplicate entry 'admin' for key 'name'") [SQL: u'INSERT INTO roles (name) VALUES (%s)'] [parameters: ('admin',)]session

查了网上的好多资料说把字段的约束unique=True去掉就行了,可是根本缘由不在这。app

缘由就是由于app.run(debug=True)。开启debug模式以后,当咱们修改代码的时候,好比将删除表和建立表这两句话注释,而后打开插入数据的注释。这个过程debug模式默认就已经把程序运行一遍了。此时数据库就已经有了数据,当咱们再次手动执行的时候,又往数据库中插入了一条数据,这时候就会报错。由于字段的约束是惟一性的unique,因此解决的办法有两种:框架

第一种:就是不要将删除表和建立表这两句话注释,每次执行都要带着这两个句话。不管是debug模式自动执行仍是咱们手动执行程序,都会先删除表而后再建立表,因此执行多少次都不怕。函数

第二种:关闭debug模式。就是这样app.run()

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2.数据库的增删改查:

1.如下的方法都是返回一个新的查询,须要配合执行器使用。

filter(): 过滤,功能比较强大。
filter_by():过滤,用在一些比较简单的过滤场景。

order_by():排序。默认是升序,降序须要导包:from sqlalchemy import * 。而后引入desc方法。好比order_by(desc("email")).按照邮箱字母的降序排序。

 

group_by():分组。

2.如下都是一些经常使用的执行器:配合上面的过滤器使用。

get():得到id等于几的函数。好比:查询id=1的对象。get(1)。切记:括号里没有“id=”,直接传入id的数值就ok。由于该函数的功能就是查询主键等于几的对象。

all():查询全部的数据。

first():查询第一个数据。

count():返回查询结果的数量。

paginate():分页查询,返回一个分页对象。paginate(参数1,参数2,参数3)

参数1:当前是第几页,参数2:每页显示几条记录,参数3:是否要返回错误。

返回的分页对象有三个属性:items:得到查询的结果,pages:得到一共有多少页,page:得到当前页。

3.经常使用的逻辑符:

须要倒入包才能用的有:from sqlalchemy import * 

not_  and_  or_   还有上面说的排序desc。

经常使用的内置的有:in_      表示某个字段在什么范围之中。

4.其余关系的一些数据库查询:

endswith():以什么结尾。

startswith():以什么开头。

contains():包含

5.下面体会一下上面的这些用法:

1. 查询全部用户数据 User.query.all() 2. 查询有多少个用户 User.query.count() 3. 查询第1个用户 User.query.first() 4. 查询id为4的用户[3种方式] User.query.get(4) User.query.filter_by(id=4).first()     User.query.filter(User.id==4).first() filter:(类名.属性名==) filter_by:(属性名=) filter_by: 用于查询简单的列名,不支持比较运算符 filter比filter_by的功能更强大,支持比较运算符,支持or_、in_等语法。 5. 查询名字结尾字符为g的全部数据[开始/包含] User.query.filter(User.name.endswith('g')).all() User.query.filter(User.name.contains('g')).all() 6. 查询名字不等于wang的全部数据[2种方式] from sqlalchemy import not_
注意了啊:逻辑查询的格式逻辑符_(类属性其余的一些判断) User.query.filter(not_(User.name
=='wang')).all() User.query.filter(User.name!='wang').all() 7. 查询名字和邮箱都以 li 开头的全部数据[2种方式] from sqlalchemy import and_ User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all() User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all() 8. 查询password是 `123456` 或者 `email` 以 `itheima.com` 结尾的全部数据 from sqlalchemy import or_ User.query.filter(or_(User.password=='123456', User.email.endswith('itheima.com'))).all() 9. 查询id为 [1, 3, 5, 7, 9] 的用户列表 User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all() 10. 查询name为liu的角色数据 关系引用 User.query.filter_by(name='liu').first().role.name 11. 查询全部用户数据,并以邮箱排序 排序 User.query.order_by('email').all() 默认升序 User.query.order_by(desc('email')).all() 降序 12. 查询第2页的数据, 每页只显示3条数据 help(User.query.paginate) 三个参数: 1. 当前要查询的页数 2. 每页的数量 3. 是否要返回错误 pages = User.query.paginate(2, 3, False) pages.items # 获取查询的结果 pages.pages # 总页数 pages.page # 当前页数

 3.使用第三方扩展框架迁移数据库文件。

使用框架须要配置的代码以下:

# -*- coding:utf-8 -*-
from flask import Flask from flask_sqlalchemy import SQLAlchemy # 操做数据库的扩展包 from flask_script import Manager # 用命令操做的扩展包 from flask_migrate import Migrate,MigrateCommand # 操做数据库迁移文件的扩展包 app = Flask(__name__) app.debug = True app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@localhost/second_flask" app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False db = SQLAlchemy(app) manager = Manager(app) # 建立迁移对象 migrate = Migrate(app,db) # 将迁移文件的命令添加到‘db’中 manager.add_command('db',MigrateCommand) class Role(db.Model): __tablename__ = "table_roles" id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(16),unique=True) info = db.Column(db.String(100)) Users = db.relationship("User",backref='role') class User(db.Model): __tablename__ = "table_users" id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(16),unique=True) info = db.Column(db.String(200)) role_id = db.Column(db.Integer,db.ForeignKey("table_roles.id")) @app.route('/') def hello_world(): return 'Hello World!'


if __name__ == '__main__': manager.run()

 

使用迁移命令以下:

好比上面的代码所在的文件名称为database.py。

1.python database.py db init    生成管理迁移文件的migrations目录

2.python database.py db migrate -m "注释"   在migrations/versions中生成一个文件,该文件记录数据表的建立和更新的不一样版本的代码。

3.python database.py db upgrade  在数据库中生成对应的表格。

4.当须要改表格的时候,改完先执行第二步,而后再执行第三步。

5.须要修改数据表的版本号的时候须要作的操做以下:

python database.py db upgrade 版本号  向上修改版本号

python database.py db downgrade 版本号   向下修改版本号

可能用到的其余的语句:

python database.py db history    查看历史版本号

python database.py db current   查看当前版本号