Flask开发系列之数据库操作
Flask开发系列之数据库操作
Python数据库框架
我们可以在Flask中使用MySQL、Postgres、SQLite、Redis、MongoDB 或者 CouchDB。
还有一些数据库抽象层代码包供选择,例如 SQLAlchemy 和MongoEngine。你可以使用这些抽象包直接处理高等级的 Python 对象,而不用处理如表、文档或查询语言此类的数据库实体。
使用Flask-SQLAlchemy管理数据库
我们选择使用的数据库框架是 Flask-SQLAlchemy(http://pythonhosted.org/Flask-SQLAlchemy/),这个 Flask 扩展包装了 SQLAlchemy(http://www.sqlalchemy.org/)框架。
Flask-SQLAlchemy 是一个 Flask 扩展,简化了在 Flask 程序中使用 SQLAlchemy 的操作。
SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy 提供了高层 ORM,也提供了使用数据库原生 SQL 的低层功能。
安装
(venv) $ pip install flask-sqlalchemy
在 Flask-SQLAlchemy怎么使用数据库
在 Flask-SQLAlchemy 中,数据库使用 URL 指定。最流行的数据库引擎采用的数据库 URL。
FLask-SQLAlchemy数据库URL如下所示:
数据库引擎 URL MySQL mysql://username:password@hostname/database Postgres postgresql://username:password@hostname/database SQLite(Unix) sqlite:////absolute/path/to/database SQLite(Windows) sqlite:///c:/absolute/path/to/database
在这些 URL 中,hostname 表示 MySQL 服务所在的主机,可以是本地主机(localhost),
也可以是远程服务器。数据库服务器上可以托管多个数据库,因此 database 表示要使用的
数据库名。如果数据库需要进行认证,username 和 password 表示数据库用户密令。
注意:SQLite 数据库不需要使用服务器,因此不用指定 hostname、username 和password。URL 中的 database 是硬盘上文件的文件名。
配置数据库
程序使用的数据库 URL 必须保存到 Flask 配置对象的 SQLALCHEMY_DATABASE_URI 键中。配置对象中还有一个很有用的选项,即 SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True时,每次请求结束后都会自动提交数据库中的变动。其他配置选项的作用请参阅 Flask-SQLAlchemy 的文档。
test.py
from flask_sqlalchemy import SQLAlchemy from flask import Flask import os basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] =\ 'sqlite:///' + os.path.join(basedir, 'data.sqlite') app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app)
db 对象是 SQLAlchemy 类的实例,表示程序使用的数据库,同时还获得了 Flask-SQLAlchemy提供的所有功能。
定义模型
模型这个术语表示程序使用的持久化实体。在 ORM 中,模型一般是一个 Python 类,类中的属性对应数据库表中的列。
test.py:定义 Role 和 User 模型
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) def __repr__(self): return '<Role %r>' % self.name class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) def __repr__(self): return '<User %r>' % self.username
类变量 __tablename__ 定义在数据库中使用的表名。如果没有定义 __tablename__ ,Flask-SQLAlchemy 会使用一个默认名字,但默认的表名没有遵守使用复数形式进行命名的约定,所以最好由我们自己来指定表名。
其余的类变量是该模型的属性,被定义为 db.Column类的实例。
注意:Flask-SQLAlchemy 要求每个模型都要定义 主键 ,这一列经常命名为 id 。
db.Column 类构造函数的第一个参数是数据库列和模型属性的类型。 最常用的SQLAlchemy列类型 类型名 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 时间间隔 Enum str 一组字符串 PickleType 任何 Python 对象 自动使用 Pickle 序列化 LargeBinary str 二进制文件 db.Column 中其余的参数指定属性的配置选项。列出了一些可用选项。 最常使用的SQLAlchemy列选项 选项名 说 明 primary_key 如果设为 True ,这列就是表的主键 unique 如果设为 True ,这列不允许出现重复的值 index 如果设为 True ,为这列创建索引,提升查询效率 nullable 如果设为 True ,这列允许使用空值;如果设为 False ,这列不允许使用空值 default 为这列定义默认值
数据库操作
创建表
(venv) $ python test.py shell
>>> from hello import db
>>> db.create_all()
如果修改模型后要把改动应用到现有的数据库中,这一特性会带来不便,它把数据库中原有的数据都销毁了。更新现有数据库表的粗暴方式是先删除旧表再重新创建:
>>> db.drop_all()
>>> db.create_all()
插入行
下面这段代码创建了一些角色和用户:
>>> from hello import Role, User
>>> admin_role = Role(name='Admin')
>>> mod_role = Role(name='Moderator')
>>> user_role = Role(name='User')
>>> user_john = User(username='john', role=admin_role)
>>> user_susan = User(username='susan', role=user_role)
>>> user_david = User(username='david', role=user_role)
通过数据库会话管理对数据库所做的改动,在 Flask-SQLAlchemy 中,会话由 db.session表示。准备把对象写入数据库之前,先要将其添加到会话中:
>>> db.session.add(admin_role)
>>> db.session.add(mod_role)
>>> db.session.add(user_role)
>>> db.session.add(user_john)
>>> db.session.add(user_susan)
>>> db.session.add(user_david)
或者简写成:
>>> db.session.add_all([admin_role, mod_role, user_role,
... user_john, user_susan, user_david])
为了把对象写入数据库,我们要调用 commit() 方法提交会话:
>>> db.session.commit()
注意:数据库会话能保证数据库的一致性。提交操作使用原子方式把会话中的对象全部写入数据库。如果在写入会话的过程中发生了错误,整个会话都会失效。如果你始终把相关改动放在会话中提交,就能避免因部分更新导致的数据库不一致性。
数据库会话也可 回滚 。调用 db.session.rollback() 后,添加到数据库会话中的所有对象都会还原到它们在数据库时的状态。
修改行
在数据库会话上调用 add() 方法也能更新模型。我们继续在之前的 shell 会话中进行操作,
下面这个例子把 "Admin" 角色重命名为 "Administrator" :
>>> admin_role.name = 'Administrator'
>>> db.session.add(admin_role)
>>> db.session.commit()
删除行
数据库会话还有个 delete() 方法。下面这个例子把 "Moderator" 角色从数据库中删除:
>>> db.session.delete(mod_role)
>>> db.session.commit()
注意,删除与插入和更新一样,提交数据库会话后才会执行。
查询行
1.Flask-SQLAlchemy 为每个模型类都提供了 query 对象。最基本的模型查询是取回对应表中的所有记录:
>>> Role.query.all()
[<Role u'Administrator'>, <Role u'User'>]
>>> User.query.all()
[<User u'john'>, <User u'susan'>, <User u'david'>]
2.使用过滤器可以配置 query 对象进行更精确的数据库查询。下面这个例子查找角色为"User" 的所有用户:
>>> User.query.filter_by(role=user_role).all()
[<User u'susan'>, <User u'david'>]
3.若要查看 SQLAlchemy 为查询生成的原生 SQL 查询语句,只需把 query 对象转换成字符串:
>>> str(User.query.filter_by(role=user_role))
'SELECT users.id AS users_id, users.username AS users_username,
users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'
4.如果你退出了 shell 会话,前面这些例子中创建的对象就不会以 Python 对象的形式存在,而
是作为各自数据库表中的行。如果你打开了一个新的 shell 会话,就要从数据库中读取行,
再重新创建 Python 对象。下面这个例子发起了一个查询,加载名为 "User" 的用户角色:
>>> user_role = Role.query.filter_by(name='User').first()
5.filter_by() 等过滤器在 query 对象上调用,返回一个更精确的 query 对象。多个过滤器可以一起调用,直到获得所需结果。下表列出了可在 query 对象上调用的常用过滤器。完整的列表参见 SQLAlchemy 文档
(http://docs.sqlalchemy.org)。
常用的SQLAlchemy查询过滤器
过滤器 说 明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit() 使用指定的值限制原查询返回的结果数量,返回一个新查询
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询
6.在查询上应用指定的过滤器后,通过调用 all() 执行查询,以列表的形式返回结果。除了all() 之外,还有其他方法能触发查询执行。下表 列出了执行查询的其他方法。
最常使用的SQLAlchemy查询执行函数
方 法 说 明 all() 以列表形式返回查询的所有结果 first() 返回查询的第一个结果,如果没有结果,则返回 None first_or_404() 返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应 get() 返回指定主键对应的行,如果没有对应的行,则返回 None get_or_404() 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应 count() 返回查询结果的数量 paginate() 返回一个 Paginate 对象,它包含指定范围内的结果
(1) SQLAlchemy操作sql原生
安装操作数据库的模块
pip3 install pymysql
安装 flask-sqlalchemy
pip3 install flask-sqlalchemy
配置路径
DB_URI = ‘mysql+pymysql://root:password@host:port/database’
下面先看下sqlalchemy操作的写法:
from sqlalchemy import create_engine
HOST = '127.0.0.1'
USERNAME = 'root'
PASSWORD = '123456'
DATABASE = 'demo' #数据库名
PORT = 3306
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOST,PORT,DATABASE)
#创建引擎
engine = create_engine(DB_URI)
with engine.connect() as db:
data = db.execute('select * from user') #从user表中获取全部数据
db.execute('delete from user where id=1') #删除id=1的数据
(2) 设计数据表
1 字段类型
类型名 | python中的类型 | 说明 |
---|---|---|
Integer | int | 存储整形 32位 |
SmallInteger | int | 小整形 16为 |
BigInteger | int | 大整形 |
Float | float | 浮点数 |
String | str | 字符串 varchar |
Text | str | 长文本 |
Boolean | bool | bool值 |
Date | datetimedate | 日期 |
Time | datetime.time | 时间 |
datetime | datetime.datetime | 时间日期 |
2 可选条件
选项 | 说明 |
---|---|
primary_key | 主键, 如果设为True,表示主键 |
unique | 唯一索引 ,如果设为True,这列唯一 |
index | 常规索引, 如果设为True,创建索引,提升查询效率 |
nullable | 是否可以为null 默认True |
default | 默认值 |
(3)在flask中使用ORM模型
下面我们使用ORM模型
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:20111673@127.0.0.1:3306/demo'
db = SQLAlchemy(app) #
manager = Manager(app)
#创建User用户,表名为user
class User(db.Model):
__table__name = 'user'
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(20),index=True)
sex = db.Column(db.Boolean,default=True)
info = db.Column(db.String(50))
# 定义一个视图函数
@app.route('/create')
def create():
# db.drop_all() #删除仅为模型表
db.create_all() #创建模型表
return '创建成功'
if __name__ == '__main__':
manager.run()
(4)增加数据
添加数据方式1
#方式1
# sqlalchemy默认开启了事务处理
@app.route('/insert/')
def insert():
try:
u = User(username='WANGWU',info='personal WANGWU message')
db.session.add(u) #添加数据对象
db.session.commit() #事务提交
except:
db.session.rollback()#事务回滚
return '添加单条数据!'
@app.route('/insertMany/')
def insertMany():
u1 = User(username='name1',info='personal name1 message')
u2 = User(username='name2',info='personal name2 message')
db.session.add_all([u1,u2]) #以add_all(数据对象列表)
db.session.commit() #
return '添加多条数据!'
添加数据方式2
#方式2
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True #在app设置里开启自动提交
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #关闭数据追踪,避免内存资源浪费
@app.route('/insertMany/')
def insertMany():
u1 = User(username='name1',info='personal name1 message')
u2 = User(username='name2',info='personal name2 message')
db.session.add_all([u1,u2])
return '提交多条数据'
(5)更新与删除
# 类名.query 返回对应的查询集
# 类名.query.get(查询条件) 返回对应的查询对象
@app.route('/update/')
def update():
u = User.query.get(1)
u.username = 'update name' #更新内容
db.session.add(u) #进行添加
return 'update'
# 删除数据
@app.route('/delete/')
def delete():
u = User.query.get(2) #找到对应的查询集对象
db.session.delete(u) # 删除对应的u对象
return 'delete id=2'
(6) 拆分MVT
目录结构
project/
manage.py #启动项存放
ext.py #作为当前sqlalchemy扩展
settings.py #配置存放
app/
__init__.py
models.py #应用models.py
views.py #应用视图views.py
templates/ #模板目录
static/ #静态文件目录
ext.py SQLAlchemy扩展
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() #实例化db对象
蓝本view view.py视图函数
from flask import Blueprint
from .models import User
from ext import db
#创建蓝本view
view = Blueprint('view',__name__)
#定义视图函数
@view.route('/')
def index():
return 'index'
@view.route('/insert/')
def insert():
u = User(username='张三',info='个人信息')
db.session.add(u)
return 'insert success'
蓝本view models.py模型类
from ext import db #导入db
#构建User模型类
class User(db.Model,Base):
__table__name = 'user'
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(20),index=True)
sex = db.Column(db.Boolean,default=True)
info = db.Column(db.String(50))
manage.py启动项
from flask import Flask
from flask_script import Manager
from ext import db
import settings
from app.view import view
app = Flask(__name__)
#将系统配置项Config类加载到app
app.config.from_object(settings.Config)
#通过db对象将app初始化
db.init_app(app)
#将蓝图view注册进app
app.register_blueprint(view)
manager = Manager(app)
if __name__ == '__main__':
manager.run()
setting.py配置文件
class Config:
#设置mysql+pymysql的连接
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:20111673@127.0.0.1:3306/demo'
#加密设置
SECRETE_KEY = 'secret_key'
#关闭数据追踪
SQLALCHEMY_TRACK_MODIFICATIONS = False
#开启提交
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
前面我们采用系统的每次自动提交session 即SQLALCHEMY_COMMIT_ON_TEARDOWN
但是如果想自己定义提交方式,同时不想传入关键字参数,那么该怎样入手呢?这里提供一种思路
(7) 自定义增删改类
我们对模型类进行了修改,models.py 内容如下:
from ext import db
#定义了base基类
class Base:
def save(self):
try:
db.session.add(self) #self实例化对象代表就是u对象
db.session.commit()
except:
db.session.rollback()
#定义静态类方法接收List参数
@staticmethod
def save_all(List):
try:
db.session.add_all(List)
db.session.commit()
except:
db.session.rollback()
#定义删除方法
def delete(self):
try:
db.session.delete(self)
db.session.commit()
except:
db.session.rollback()
#定义模型user类
class User(db.Model,Base):
__table__name = 'user'
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(20),index=True)
sex = db.Column(db.Boolean,default=True)
info = db.Column(db.String(50))
#
def __init__(self,username='',info='',sex=True):
self.username = username
self.info = info
self.sex = sex
#注意:
#原实例化: u = User(username='张三',info='个人信息')
#现实例化: u = User('李四','李四个人信息')
在views.py中使用
from flask import Blueprint
from .models import User
from ext import db
view = Blueprint('view',__name__)
@view.route('/')
def index():
return 'index'
#插入单条数据
@view.route('/insert/')
def insert():
# u = User(username='test',info='default')
u = User('xiaomeng','default')
u.save()
db.session.add(u)
return 'insert success'
#保存多条数据
@view.route('/saveMany/')
def saveMany():
u1 = User('zhan123','default123')
u2 = User('li123','default message')
User.save_all([u1,u2])
return 'add many'
#删除数据
@view.route('/delete/')
def delete():
u = User.query.get(1) #获取查询集
u.delete()
return 'delete message'
其他都不做改变,基本思路是封装到类,通过多继承来实现方法的调用。
转载:https://yq.aliyun.com/articles/610817