August Rush

一个还在努力成长的小火汁!

游龙当归海,海不迎我自来也。

We create our own demons.

You can reach me at augustrush0923@gmail.com
SQLAlchemy
发布:2022年02月13日 | 作者:augustrush | 阅读量: 710

介绍

SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

架构图

  • Schema/Types:定义了类到表之间的映射框架(规则)

  • SQL Expression Language: 封装好的 SQL 语句

  • Engine:操作者

  • Connection Pooling:连接池

  • Dialect:根据用户的配置,调用不同的数据库 API(Oracle, postgresql, Mysql) 并执行对应的 SQL语句

SQLAlchemy提供了两种主要的使用模式

  1. SQL表达式语言(SQLAlchemy Core)
  2. ORM

应该选择哪种模式?

  • 虽然你使用的框架中已经内置了ORM,但是希望添加更强大的报表功能,请选用Core。
  • 如果你想在一个一模式为中心的视图中查看数据(用户类似于SQL),请使用Core。
  • 如果你的数据不需要业务对象,请使用Core。
  • 如果你要把数据看作业务对象,请使用ORM。
  • 如果你想快速创建原型,请使用ORM。
  • 如果你需要同事使用业务对象和其他与问题域无关的数据,请组合使用Core和ORM。

安装

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()第一次返回的引擎,其实并没有试图连接到数据库之中; 只有在第一次要求它对数据库执行任务时才会发生这种情况。

SQLAlchemy ORM

声明映射表

orm使用的类应该满足如下四个要求:

  • 继承自declarative_base对象。
  • 包含__tablename__,这是数据库中使用的表名。
  • 包含一个或多个属性,它们都是column对象。
  • 确保一个或多个属性组成主键。

使用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()

通过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构建

京ICP备20007446号-1 & 豫公网安备 41100202000460号

网站地图 & RSS | Feed