【1】ORM - SQLAlchemy操作MySQL数据库

优先(官方文档SQLAlchemy-version1.2): sqlalchemy | 作者:斯芬克斯
推荐一(长篇幅version1.2.0b3):python约会之ORM—sqlalchemy | 作者:大牧莫邪
推荐二(短篇幅): 使用SQLAlchemy | 作者:廖雪峰
参考(长篇幅): Python中操作SQLAlchemy | 作者:俊采星驰_87e0

备注:本篇文章基于python3环境下使用sqlalchemy。

ORM介绍(作用:不用原生SQL语句对数据库操作)

一、什么是orm(orm是一种术语而不是软件)

1)orm英文全称object relational mapping,就是对象映射关系程序
2)简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的
3)为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系
4)这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言

总结:类似把C盘深层次文件或文件夹拉到桌面,本质也是映射磁盘位置信息,其实也与快捷方式图标启动应用程序也有异曲同工之妙。ORM就是用面向对象的方式操作mysql数据库。

二、ORM作用

1)隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
2)ORM使我们构造固化数据结构变得简单易行。

三、ORM缺点

1)无可避免的,自动化意味着映射和关联管理,代价是牺牲性能
2)现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。


目录

  1. SQLAlchemy基础操作
    1.1 安装
    1.2 连接引擎
    1.3 连接会话
  2. ORM之Object操作
    2.1 基础类
    2.2 数据类型创建
    2.3 数据类型映射操作
    2.4 增加和更新
  3. SQLAlchemy核心操作(数据的查询)
    3.1 查询对象Query
        3.1.1 常规查询query
        3.1.2 指定排序查询
        3.1.3 指定列查询
        3.1.4 指定列属性别名
        3.1.5 指定类型别名
        3.1.6 切片查询
    3.2 条件筛选filter
        3.2.1 等值条件 — equals / not equals
        3.2.2 模糊条件 — like
        3.2.3 范围条件 — in / not in
        3.2.4 空值条件 — is null / is not null
        3.2.5 并且条件 — AND
        3.2.6 或者条件 — OR
        3.2.7 SQL语句查询
    3.3. 查询结果
        3.3.1 all()函数返回查询列表
        3.3.2 filter()函数返回单项数据的列表生成器
        3.3.3 one()/one_or_none()/scalar()返回单独的一个数据对象

1.1 安装

首先确保你的PC已经具备了完善的python3开发环境
安装sqlalchemy,执行如下命令使用pip安装即可(推荐)

$ pip3 install sqlalchemy

或者执行如下命令通过easy_install进行安装(亲测:python3环境下使用以下命令安装偶尔会出现模块引入不到的问题)

$ easy_install sqlalchemy

安装完成之后,可以通过引入sqlalchemy进行版本查看,确认sqlalchemy安装成功

>>> import sqlalchemy
>>> sqlalchemy.__version__
'1.2.14'

1.2 连接引擎

使用sqlalchemy进行数据库操作,首先我们需要建立一个指定数据库的连接引擎对象
建立引擎对象的方式被封装在了sqlalchemy.create_engine函数中,通过指定的数据库连接信息就可以进行创建

创建数据库连接引擎时参数设置语法:

# 语法规则:dialect[+driver]://user:password@host/dbname[?key=value..]
# 引入建立引擎的模块
from sqlalchemy import create_engine
# 创建一个和mysql数据库之间的连接引擎对象
engine = create_engine("mysql://root:root@localhost/py1709", 
encoding="utf-8", echo=True)

指定的数据库连接字符串表示了目标数据库的配置信息;encoding配置参数指定了和和数据库之间交换的数据的编码方式,同时echo参数表示随时在控制台展示和数据库之间交互的各种信息
create_engine()函数返回的是sqlalchemy最核心的接口之一,该引擎对象会根据开发人员指定的数据库进行对应的sql api的调用处理
连接postgresql数据库:
engine = create_engine("postgresql://scott:tiger@localhost/test")
连接mysql数据库:
engine = create_engine("mysql://scott:tiger@hostname/dbname",
encoding='utf-8', echo=True)
其他连接方式请参考官方文档:http://docs.sqlalchemy.org/en/latest/

1.3 连接会话

创建了数据库连接引擎对象之后,我们需要获取和指定数据库之间的连接,通过连接进行数据库中数据的增删改查操作,和数据库的连接我们称之为和指定数据库之间的会话,通过指定的一个模块

sqlalchemy.sessionmaker进行创建
# 引入创建session连接会话需要的处理模块
from sqlalchemy.orm import sessionmaker
# 创建一个连接会话对象;需要指定是和那个数据库引擎之间的会话
Session = sessionmaker(bind=engine)
session = Session()
# 接下来~就可以用过session会话进行数据库的数据操作了。

PS:如果在创建会话的时候还没有指定数据库引擎,可以通过如下的方式完成会话操作

Session = sessionmaker()
..
Session.configure(bind=engine)
session = Session()
..

2. ORM之Object操作

我们的程序中的对象要使用sqlalchemy的管理,实现对象的orm操作,就需要按照框架指定的方式进行类型的创建操作,sqlalchemy封装了基础类的声明操作和字段属性的定义限制方式,开发人员要做的事情就是引入需要的模块并在创建对象的时候使用它们即可

基础类封装在sqlalchemy.ext.declarative.declarative_base模块中
字段属性的定义封装在sqlalchemy模块中,通过sqlalchemy.Column定义属性,通过封装的Integer、String、Float等定义属性的限制

2.1 基础类

创建基础类的方式如下:

# 引入需要的模块
from sqlalchemy.ext.declarative import declarative_base

# 创建基础类
BaseModel = declarative_base()

2.2 数据类型创建

创建数据模型的操作

# 引入需要的模块
from sqlalchemy import Column, String, Integer

# 创建用户类型
class User(BaseModel):
    # 定义和指定数据库表之间的关联
    __tabelname__ = “user”
    # 创建字段类型
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    age = Column(Integer)

PS:定义的数据类型必须继承自之前创建的BaseModel,同时通过指定tablename确定和数据库中某个数据表之间的关联关系,指定某列类型为primary_key设定的主键,其他就是通过Column指定的自定义属性了。
sqlalchemy会根据指定的tablename和对应的Column列字段构建自己的accessors访问器对象,这个过程可以成为instrumentation,经过instrumentation映射的类型既可以进行数据库中数据的操作了。

2.3 数据类型映射操作

完成了类的声明定义之后,Declarative会通过python的metaclass对当前类型进行操作,根据定义的数据类型创建table对象,构建程序中类型和数据库table对象之间的映射mapping关系

通过类型对象的metadata可以实现和数据库之间的交互,有需要时可以通过metadata发起create table操作,通过Base.metadata.create_all()进行操作,该操作会检查目标数据库中是否有需要创建的表,不存在的情况下创建对应的表

..

if __name__ == “__main__”:
Base.metadata.create_all(engine)
..

2.4 增加和更新

下面就是核心的数据对象的处理了,在程序代码中根据定义的数据类型创建对象的方式比较简单,执行如下的操作创建一个对象:

$ user = User(name=”tom”, age=18)
$ print(user.name)
tom
$ print(user.id)
None

通过会话对象将对象数据持久化到数据库的操作

$ session.add(user)
$ print(user.id)
None
$ session.commit()
$ print(user.id)
1

3.1 查询对象Query

Session是sqlalchemy和数据库交互的桥梁,Session提供了一个Query对象实现数据库中数据的查询操作

3.1.1 常规查询query

直接指定类型进行查询

user_list = session.query(User)
for user in user_list:
    print(user.name)

3.1.2 指定排序查询

通过类型的属性指定排序方式

user_list = session.query(User).order_by(User.id) # 默认顺序
user_list = session.query(User).order_by(-User.id) # 指定倒序
user_list = session.query(User).order_by(-User.id, User.name) # 多个字段

3.1.3 指定列查询

指定查询数据对象的属性,查询目标数据

user_list = session.query(User, User.name).all()
for u in user_list:
    print(u.User, u.name)

3.1.4 指定列属性别名

对于名称较长的字段属性,可以指定名称在使用时简化操作

user_list = session.query(Usre.name.label(‘n’)).all()

for user in user_list:
    print(user.n)

3.1.5 指定类型别名

对于类型名称较长的情况,同样可以指定别名进行处理

from sqlalchemy.orm import aliased

user_alias = aliased(User, name=’u_alias’)

user_list = session.query(u_alias, u_alias.name).all()
for u in user_list:
    print(u.u_alias, u.name)

3.1.6 切片查询

对于经常用于分页操作的切片查询,在使用过程中直接使用python内置的切片即可

user_list = session.query(User).all()[1:3]
..

3.2 条件筛选filter

前一节中主要是对于数据查询对象query有一个比较直观的感受和操作,在实际使用过程中经常用到条件查询,主要通过filter和filter_by进行操作,重点讲解使用最为频繁的filter条件筛选函数

3.2.1 等值条件——equals / not equals
# equals
session.query(User).filter(User.id == 1) # 相等判断
# not equals
session.query(User).filter(User.name != ‘tom’)# 不等判断

3.2.2 模糊条件——like
session.query(User).filter(User.name.like(‘%tom%’))

3.2.3 范围条件——in / not in
# IN
session.query(User).filter(User.id.in_([1,2,3,4]))

session.query(User).filter(User.name.in_([
     session.query(User.name).filter(User.id.in_[1,2,3,4])
]))

# NOT IN
session.query(User).filter(~User.id.in_([1,2,3]))

3.2.4 空值条件——is null / is not null
# IS NULL
session.query(User).filter(User.name == None)
session.query(User).filter(User.name.is_(None)) # pep8

# IS NOT NULL
session.query(User).filter(User.name != None)
session.query(User).filter(User.name.isnot(None)) # pep8

3.2.5 并且条件——AND
from sqlalchemy import and_

session.query(User).filter(User.name=’tom’).filter(User.age=12)
session.query(User).filter(User.name=’tom’, User.age=12)
session.query(User).filter(and_(User.name=’tom’, User.age=12))

3.2.6 或者条件——OR
from sqlalchemy import or_
session.query(User).filter(or_(User.name=’tom’, User.name=’jerry’))

3.2.7 SQL语句查询

某些特殊情况下,我们也可能在自己的程序中直接使用sql语句进行操作

from sqlalchemy import text
session.query(User).from_statement(
text(‘select * from users where name=:name and age=:age’))
.params(name=’tom’, age=12).all()

3.3 查询结果

3.3.1 all()函数返回查询列表
session.query(User).all()
[..]

3.3.2 filter()函数返回单项数据的列表生成器
session.query(User).filter(..)
<..>

3.3.3 one()/one_or_none()/scalar()返回单独的一个数据对象
session.query(User).filter(..).one()/one_or_none()/scalar()
..

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容