SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
Schema/Types
:定义了类到表之间的映射框架(规则)
SQL Expression Language
: 封装好的 SQL 语句
Engine
:操作者
Connection Pooling
:连接池
Dialect
:根据用户的配置,调用不同的数据库 API(Oracle, postgresql, Mysql) 并执行对应的 SQL语句
pip install sqlalchemy
SQLAlchemy本身无法操作数据库,其必须使用 pymsql 等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作。
# MySQL-Python
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
# pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
# MySQL-Connector
mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
# cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
# 更多:http://docs.sqlalchemy.org/en/latest/dialects/index.html
要连接到数据库,需要先创建一个SQLAlchemy引擎。SQLAlchemy引擎为数据库创建一个公共接口来执行SQL语句。这是通过包装数据库连接池和方言(不同数据库客户端)来实现的。
SQLAlchemy提供了一个函数来创建引擎。在这个函数中,你可以指定连接字符串,以及其他一些可选的关键字参数。
from sqlalchemy import create_engine
engine = create_engine(
"mysql+pymysql://root:123@172.16.153.160:3306/dbname?charset=utf8mb4",
echo=True,
max_overflow=5
)
echo
:参数是设置SQLAlchemy日志记录的快捷方式。启用它后,可以terminal看到所有生成的SQL。max_overflow
:指定了连接池的最大连接数。create_engine()
的返回值是一个实例引擎,它代表了一个数据库的核心接口。
此时的连接是惰性的,当create_engine()第一次返回的引擎,其实并没有试图连接到数据库之中; 只有在第一次要求它对数据库执行任务时才会发生这种情况。
orm使用的类应该满足如下四个要求:
__tablename__
,这是数据库中使用的表名。使用Declarative系统映射的类是根据基类定义的,换句话说每个映射类需要继承这个基类。我们使用declarative_base()
函数可以创建这个基类,如下所示:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
现在我们有了一个Base
,我们可以根据它定义任意数量的映射类。
from sqlalchemy import Column, Integer, String, DateTime
class Dept(Base):
__tablename__ = 'DEPT'
deptno = Column(Integer, primary_key=True, autoincrement=True, unique=True)
dname = Column(String(24))
loc = Column(String(13), nullable=True)
def __repr__(self):
return self.dname
class Emp(Base):
__tablename__ = 'EMP'
empno = Column(Integer, primary_key=True, autoincrement=True, unique=True)
ename = Column(String(10))
job = Column(String(9))
mgr = Column(Integer, nullable=True)
hiredate = Column(DateTime, default=datetime.datetime.now)
sal = Column(Integer, nullable=True)
comm = Column(Integer, nullable=True)
deptno = Column(Integer, nullable=True)
def __repr__(self):
return self.ename
class SalGrade(Base):
__tablename__ = "SALGRADE"
grade = Column(Integer, primary_key=True)
losal = Column(Integer)
hisal = Column(Integer)
def __repr__(self):
return self.grade
注意:
__repr__
方法定义了一个对象的比较易读的显式方式
使用 Declarative 的类至少需要一个__tablename__
属性,并且至少有一个 Column
属于主键。
我们可以使用MetaData
为所有数据库中尚不存在的表向数据库发出CREATE TABLE语句。
下面,我们调用该MetaData.create_all()
方法,将我们Engine
作为数据库连接源传递。
Base.metadata.create_all(engine)
执行成功后可以检查是否创建成功
from models import Dept
dept = Dept(deptno=10, dname='ACCOUNTING', loc='NEW YORK')
此时,实例对象只是在此刻环境的内存中有效,并没有在表中真正生成数据。
要想生成数据到表中,需要创建一个和数据库沟通的会话对象,利用这个会话对象对数据库中的表进行操作(增加、更新,删除、查询)
会话是SQLAlchemy ORM和数据库交互的方式。它通过引擎包装数据库连接,并为通过会话加载或与会话关联的对象提供标识映射(identity map)。标识映射是一种类似于缓存的数据结构,它包含由对象表和主键确定的一个唯一的对象列表。会话还包装了一个事务,这个事务将一直保持打开状态,直到会话提交或回滚。
为创建会话,SQLAlchemy提供了一个sessionmaker类,这个类可以确保在整个应用程序中能够使用相同的参数创建会话。sessionmaker类通过创建一个Session类来实现这一点,Session类是根据传递给sessionmaker工厂的参数配置的。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine(
"mysql+pymysql://root:123@172.16.153.160:3306/dbname?charset=utf8mb4",
encoding='utf-8',
echo=True
)
# 把当前的引擎绑定给这个会话
Session = sessionmaker(bind=engine)
# 实例化
session = Session()
def _add(session):
try:
# 单条增加
dept = Dept(deptno=10, dname='ACCOUNTING', loc='NEW YORK')
session.add(dept) # 需要先把这条数据对象添加到会话实例中
session.commit() # 再通过会话实例的 commit() 方法提交事务到数据库
except Exception as e:
print(e)
finally:
session.close()
def _add_all(session):
try:
# 多条增加
depts = [
Dept(deptno=20, dname="RESEARCH", loc='DALLAS'),
Dept(deptno=30, dname="SALES", loc='CHICAGO'),
Dept(deptno=40, dname="OPERATIONS", loc='BOSTON'),
]
session.add_all(depts)
session.commit()
except Exception as e:
print(e)
finally:
session.close()
def delete(session, id):
try:
session.query(Dept).filter_by(deptno=id).delete()
session.commit()
except Exception as e:
print(e)
finally:
session.close()
def update(session, id, dname, loc=None):
try:
session.query(Dept).filter_by(deptno=id).update({"dname": dname, "loc": loc})
session.commit()
except Exception as e:
print(e)
finally:
session.close()
session.query()的返回值是Query对象,不能使用它的返回值作为查询结果。
常用Query对象的方法:
q = session.query(User)
q.count() # 获取查询结果的数量
q.all() # 返回查询结果的list,会触发执行SQL查询
q.get(id) # 根据primary_key查询单个对象
q.as_scalar() # 返回此次查询的SQL语句
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建