Python下的ORM框架SQLAlchemy

Python下的ORM框架SQLAlchemy

简介

如果写程序用sql和程序交互,那是不是要写原生sql语句。如果进行复杂的查询,那sql语句就要进行一点一点拼接,而且不太有重用性,扩展不方便。而且写的sql语句可能不高效,导致程序运行也变慢。
为了避免把sql语句写死在代码里,有没有一种方法直接把原生sql封装好了并且以你熟悉的方式操作,像面向对象那样?
 
orm(object relational mapping),就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。

ORM 相当于把数据库也给你实例化了,在代码操作sql中级又加了orm这一层。

orm的优点:

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

缺点:

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

sqlalchemy安装

1
pip install SQLAlchemy

sqlalchemy的基本操作

连接

1
2
3
4
from sqlalchemy import create_engine

# Connecting
engine = create_engine('sqlite:///:memory:', echo=True)

定义和创建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey

# Define and Create Tables
metadata = MetaData()

users = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
Column('fullname', String),
)

addresses = Table('addresses', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', None, ForeignKey('users.id')),
Column('email_address', String, nullable=False)
)

metadata.create_all(engine)

新增

1
2
3
4
5
6
# user
for kv in dict_rep:
setattr(user, kv, dict_rep[kv])
session.add(user)
session.commit()
session.close()
单行新增
1
2
3
4
5
# Insert Expressions
ins = users.insert()
str(ins)
ins = users.insert().values(name='jack', fullname='Jack Jones')
ins.compile().params
多行新增
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Executing
conn = engine.connect()
result = conn.execute(ins)
ins.bind = engine
str(ins)
result.inserted_primary_key

# Executing Multiple Statements
ins = users.insert()
conn.execute(ins, id=2, name='wendy', fullname='Wendy Williams')

conn.execute(addresses.insert(), [
{'user_id': 1, 'email_address' : 'jack@yahoo.com'},
{'user_id': 1, 'email_address' : 'jack@msn.com'},
{'user_id': 2, 'email_address' : 'www@www.org'},
{'user_id': 2, 'email_address' : 'wendy@aol.com'},
])

修改

1
2
3
4
5
6
7
# dict_rep 待修改参数
user = session.query(user).filter_by(id=int(pk)).first()
for kv in dict_rep:
setattr(user, kv, dict_rep[kv])
session.add(user)
session.commit()
session.close()
1
2
3
4
5
6
7
8
9
10
table = sqlalchemy.Table('stuff', md, autoload=True)
upd = table.update(values={table.c.foo:table.c.foo+1})


session.execute(update(stuff_table, values={stuff_table.c.foo: stuff_table.c.foo + 1}))
session.commit()

session.query(Stuff).update({Stuff.foo: Stuff.foo + 1})
session.commit()
session.close()

删除

1
2
3
4
o = session.query(user).filter_by(id=id).first()
session.delete(o)
session.commit()
session.close()

查询

1
curdatabase = session.query(users).filter_by(name='test').first()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sqlalchemy.sql import select
s = select([users])
result = conn.execute(s)

for row in result:
print(row)

result = conn.execute(s)
row = result.fetchone()
print("name:", row['name'], "; fullname:", row['fullname'])

ow = result.fetchone()
print("name:", row[1], "; fullname:", row[2])

for row in conn.execute(s):
print("name:", row[users.c.name], "; fullname:", row[users.c.fullname])

result.close()