sqlalchemy是一个操作关系型数据库的ORM工具。下面研究一下单独使用和其在flask框架中的使用方法。
直接使用sqlalchemy操作数据库
安装sqlalchemy
pip install sqlalchemy
初始化及操作数据库
# 导入:
from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 创建对象的基类:
Base = declarative_base()
class User(Base):
'''用戶信息表'''
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(80), unique=True)
email = Column(String(320), unique=True)
password = Column(String(32), nullable=False)
user = User(username='ming', email='dddd', password='1234567')
# 初始化数据库连接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)
# 创建单个会话
session = DBSession()
session = db_session()
session.add(user)
session.commit()
session.close()
# 通过创建会话池连接
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
session = db_session()
session.add(user)
session.commit()
session.close()
# 也可以创建连接
con = engine.connect()
con.execute("一个表对象",name='ffff',email='dddd', password='1234567')
con.close()
在flask框架中集成使用
安装
pip install Flask-SQLAlchemy
- 如果需要操作mysql数据库,还需要安装pymysql;
pip install pymysql
配置文件
- Flask-SQLAlchemy可以将关于SQLAlchemy的配置集成到flask的配置文件中去,在初始化app的时候一起加载。相关的配置键有:
SQLALCHEMY_DATABASE_URI
用于连接数据的数据库。例如:
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://caiwp:mysql@192.168.1.23:3307/tms_mysql?charset=utf8'
其格式为:mysql://username:password@server/db?编码
注意默认使用mysqldb连接数据库,要使用pymysql就需要用mysql+pymysql的格式;
SQLALCHEMY_COMMIT_ON_TEARDOWN
设置是否在每次连接结束后自动提交数据库中的变动。
example:
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
SQLALCHEMY_BINDS
一个映射绑定 (bind) 键到 SQLAlchemy 连接 URIs 的字典。他可以用来连接多个数据库。
example:
SQLALCHEMY_BINDS = {
'users': 'mysqldb://localhost/users',
'appmeta': 'sqlite:////path/to/appmeta.db'
}
# 上面除了默认的连接外,又连接了两个数据库,分别命名users,appmeta。在创建模型的时候可以为相应的操作定制化;
# 更多的详细参考:http://www.pythondoc.com/flask-sqlalchemy/binds.html#binds
SQLALCHEMY_ECHO
如果设置成 True,SQLAlchemy 将会记录所有发到标准输出(stderr)的语句,这对调试很有帮助;默认为false;
如:
SQLALCHEMY_ECHO = True
SQLALCHEMY_RECORD_QUERIES
可以用于显式地禁用或者启用查询记录。查询记录 在调试或者测试模式下自动启用。
一般我们不设置。
SQLALCHEMY_NATIVE_UNICODE
可以用于显式地禁用支持原生的unicode。
SQLALCHEMY_POOL_SIZE
数据库连接池的大小。默认是数据库引擎的默认值 (通常是 5)。
如:
SQLALCHEMY_POOL_SIZE = 10
SQLALCHEMY_TRACK_MODIFICATIONS
如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存,如果不必要的可以禁用它。
example:
SQLALCHEMY_TRACK_MODIFICATIONS = Flase
SQLALCHEMY_MAX_OVERFLOW
控制在连接池达到最大值后可以创建的连接数。当这些额外的连接使用后回收到连接池后将会被断开和抛弃。保证连接池只有设置的大小;
如:
SQLALCHEMY_MAX_OVERFLOW = 5
SQLALCHEMY_POOL_TIMEOUT
指定数据库连接池的超时时间。默认是 10。
example:
SQLALCHEMY_POOL_TIMEOUT = 10
SQLALCHEMY_POOL_RECYCLE
自动回收连接的秒数。这对MySQL是必须的,默认情况下MySQL会自动移除闲置8小时或者以上的连接,Flask-SQLAlchemy会自动地设置这个值为 2 小时。也就是说如果连接池中有连接2个小时被闲置,那么其会被断开和抛弃;
手动设置:
SQLALCHEMY_POOL_RECYCLE = 1200
常用配置
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://caiwp:mysql@192.168.1.23:3307/tms_mysql?charset=utf8'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
# 下面两项调试阶段启动,部署时关闭
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_ECHO = True
常用的字段、关系类型
- 常用的字段
类型名 python类型 说明
Integer int 普通整数,一般是32位
SmallInteger int 取值范围小的整数,一般是16位
BigInteger int或long 不限制精度的整数
Float float 浮点数
Numeric decimal.Decimal 普通整数,一般是32位
String str 变长字符串
Text str 变长字符串,对较长或不限长度的字符串做了优化
Unicode unicode 变长Unicode字符串
UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean bool 布尔值
Date datetime.date 时间
Time datetime.datetime 日期和时间
LargeBinary str 二进制文件
Enum enum 枚举类型
- 常用列选项
primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值,如default=1
- 常用的关系选项
backref 在关系的另一模型中添加反向引用,用于找到父表
primary join 明确指定两个模型之间使用的联结条件
uselist 如果为False,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定多对多中记录的排序方式
secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
创建模型类
from flask.ext.sqlalchemy import SQLAlchemy
# 指定一个字段为外键,必须使用类
from sqlalchemy.schema import ForeignKey
# 创建一个db对象
db = SQLAlchemy()
class User(db.Model):
__bind_key__ = 'xxx' # 可以指定为哪个数据库定义表
__tablename__ = 'users' # 定义表的名字
# 定义表中的列字段,接收所有相关的对字段的定义的信息
id = db.Column(db.Integer, primary_key=True) # 如果第一个参数是一个字符串,那么使用该字符串作为字段名
username = db.Column(db.String(80), unique=True)
# 定义相关联的表,backref为Address赋予了一个新的属性,让Address可以通过address.person找到user表
addresses = db.relationship('Address', backref='person',
lazy='dynamic')
# 可以手动初始化,也可以不做,那么会自动使用字段的变量名作为字段名
def __init__(self, username, email):
self.username = username
self.email = email
# 输出字符串
def __repr__(self):
return '<User %r>' % self.username
class Address(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50))
# 指定外键
person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
#也可以直接创建表,一般用于多对多关系
tags = db.Table('uesrs',
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
)
引入上下文
SQLAlchemy是一个全局对象,如果有多个应用程序的话,必须要让SQLAlchemy对象知道当前服务于哪个app。
# 如果只有一个app,可以创建时初始化
app = Flask(__name__)
db = SQLAlchemy(app)
# 如果有多个应用
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
# 这个函数其读取app的配置参数,将和数据库相关的配置加载到SQLAlchemy对象中
db.init_app(app)
return app
数据库的操作
- 创建和删除表
# 删除所有的表,bind参数可以指定为哪一个数据库创建表,默认为__all__,所有的数据库;
# app传入是为了获取初始化的相关参数,如果db已经初始化,则不需要传入
db.drop_all(bind="",app=app)
# 创建所有的表,其参数和drop_all是一样的
db.create_all()
- 数据的增删改查
# 首先创建一个实例
user = User(username='aaa')
# 插入一条数据,这时会发出一条insert语句,但是该事务还没有提交,可以放弃
# 每个add操作都是一个数据
db.session.add(user)
# 批量添加数据
db.session.add_all([user1,user2])
# 删除数据
db.session.delete(user1)
# 提交给数据库
db.session.commit()
# 更新数据
User.query.filter_by(name='xxx').update({'name':'li'})
# 查询query属性
User.query.filter().all()
- 过滤器的使用
# 常用的过滤器
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit() 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询
# 精确查询
person = User.query.filter_by(name='aaa',id='23').all()
# 模糊查询,
persons = User.query.filter(User.name.endswith('g')).all()
User.query.filter(User.id>3).all()
# 按username排序
User.query.order_by(User.username)
# 限制返回3个数据
User.query.limit(3).all()
# 条件查询
# 逻辑非
User.query.filter(User.name!='xxx').all()
# 逻辑与
from sqlalchemy import and_
User.query.filter(and_(User.name!='xxx',User.address.endwith('g')).all()
# 逻辑或
User.query.filter(or_(User.name!='xxx',User.address.endwith('g'))).all()
# 取反,名字不是xxx的所有
User.query.filter(not_(User.name=='xxx')).all()
- 执行器的使用
all() 以列表形式返回查询的所有结果
first() 返回查询的第一个结果,如果未查到,返回None
first_or_404() 返回查询的第一个结果,如果未查到,返回404
get() 返回指定主键对应的行,如不存在,返回None
get_or_404() 返回指定主键对应的行,如不存在,返回404
count() 返回查询结果的数量
paginate() 返回一个Paginate对象,它包含指定范围内的结果
# 使用主键查询,id = 1
User.query.get(1)
数据库的迁移
-
我们可以使用create_all()函数来创建数据库的表,不过在flask中有更加完善的管理工具flask-migrate;
-
安装
pip install flask-migrate
- 实例
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager
app = Flask(__name__)
manager = Manager(app)
db = SQLAlchemy(app)
#第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例
migrate = Migrate(app,db)
#manager是Flask-Script的实例,这条语句在flask-Script中添加一个db命令
manager.add_command('db',MigrateCommand)
# 生成相关的迁移文件,创建migrations文件夹,这个文件在项目的目录下
python manage.py db init
# 生成迁移脚本,生成upgrade()和downgrade()函数的内容,这是将要执行的操作;
python manage.py db migrate -m '修改说明'
#更新数据库
python manage.py db upgrade
# 如果需要历史版本,回退
python manage.py db history # 先查询历史版本
# 执行回退
python manage.py db downgrade 版本号