使用Python数据库ORM SQLAlchemy

来源:互联网 发布:下载淘宝网软件 编辑:程序博客网 时间:2024/05/22 11:17

文章中的有些内容借鉴了
http://wangye.org/blog/archives/724/
http://www.zouyesheng.com/sqlalchemy.html#toc7

1>python的数据库ORM(Object Relational Mapper)有什么作用?

 ORM是对象关系映射,ORM主要是按照统一的标准把数据库中的关系数据映射成程序中的对象。对数据库中的表的sql操作,可以通过超python程序对类的操作完成。
 关于ORM的介绍,可以读文章http://www.cnblogs.com/tonybinlj/archive/2008/01/10/1032728.html。

2>创建连接:

SQLAlchemy 的连接创建是 Lazy 的方式, 即在需要使用时才会去真正创建. 未真正使用之前做的工作, 全是"定义".

连接的定义是在 engine 中做的.

2.1. Engine

engine 的定义包含了三部分的内容, 一是具体数据库类型的实现, 二是连接池, 三是策略(即 engine 自己的实现).

所谓的数据库类型即是 MYSQL , Postgresql , SQLite 这些不同的数据库.

一般创建 engine 是使用 create_engine 方法:

create_engine('dialect+driver://username:password@host:port/database')
如 当使用mysql数据库时,
_ENGINE = sqlalchemy.create_engine(FLAGS.sql_connection, **engine_args)
FLAGS.sql_connection为  mysql://root:MYSQL_PASS@192.168.123.177/abc?charset=utf8 
注意:这里 指明了mysql的用户root,密码MYSQL_PASS,主机192.168.123.177,数据库abc。
这里,root用户应该有权限操作abc。否则后继建表不成功,且报错
首先,需要建数据库abc,然后授权。
$ mysql -uroot -pMYSQL_PASS
mysql> CREATE DATABASE abc;
mysql> GRANT ALL PRIVILEGES ON abc.* TO 'root'@'localhost' \
IDENTIFIED BY 'GLANCE_DBPASS';
mysql> GRANT ALL PRIVILEGES ON abc.* TO 'root'@'%' \
IDENTIFIED BY 'GLANCE_DBPASS';
mysql> FLUSH PRIVILEGES;
engine_args = {
"pool_recycle": FLAGS.sql_idle_timeout,
"echo": False,
'convert_unicode': True,
}
    第一个参数:建立数据库连接用的。
第二个参数:可以有多个。
echo=True,这么设置的话,SQLAlchemy将会通过Python标准模块logging来输出日志,如果你在操作交互式命令控制台,一些信息将会被输出,这里我们可能会看到SQLAlchemy生成的一些SQL语句,这个对于我们学习和调试是很有必要的,所以在这里我们将其设置为True,否则,如果不愿意SQLAlchemy这么啰嗦的话可以设置为False,这样就看不到这些信息啦。

连接池参数:
    - pool_size 连接数
    - max_overflow 最多多几个连接
    - pool_recycle 连接重置周期
    - pool_timeout 连接超时时间
Engine对于数据库连接的管理采取的是数据库连接池 (Pool),当连接第一次建立,SQLAlchemy将会将建立的连接放入内部的连接池中以便于随后的数据操作语句执行时复用。

2.2. Engine的策略

create_engine 的调用, 实际上会变成 strategy.create 的调用. 而 strategy 就是 engine 的实现细节. strategy 可以在 create_engine 调用时通过 strategy 参数指定, 目前官方的支持有三种:

  • plain, 默认的
  • threadlocal, 连接是线程局部的
  • mock, 所有的 SQL 语句的执行会使用指定的函数

mock 这个实现, 会把所有的 SQL 语句的执行交给指定的函数来做, 这个函数是由 create_engine  executor 参数指定: 

def f(sql,*args,**kargs):

    print sql, args, kargs

s= 'postgresql://test@localhost:5432/bbcustom'

engine = create_engine(s, strategy='mock', executor=f)

print engine.execute('select id from "user"')

3 定义类和映射

一 定义数据库中的表;二 定义python代码中就是类;三 表和类之间存在映射关系。
SQLAlchemy使用Delarative做这两件事。

SQLAlchemy使用 classic(经典模式)Modern(现代模式)两种模式 来描述一个表。

1. Classic 映射

表结构如下:
CREATE TABLE [users] (  [id]       INTEGER PRIMARY KEY,  [name]     TEXT NOT NULL,  [fullname] TEXT NOT NULL,  [password] TEXT NOT NULL);
描述一张user表
from sqlalchemy import Table, MetaData, Column, Integer, String metadata = MetaData() user = Table('users', metadata,            Column('id', Integer, primary_key=True),            Column('name', String(50)),            Column('fullname', String(50)),            Column('password', String(12))        )
user表对应的python类User:
class User(object):    def __init__(self, name, fullname, password):        self.name = name        self.fullname = fullname        self.password = password
定义user表和User类之间的映射关系:
from sqlalchemy.orm import mappermapper(User, user)
mapper(python类名,表名)

2. Modern映射

只需定义映射类

获取Declarative基类
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()
其它所有映射类必须继承该基类
class SomeClass(Base):
    __tablename__ = 'some_table'    id = Column(Integer, primary_key=True)    name =  Column(String(50))
定义完SomeClass类,产生Table和mapper(),可通过如下方式获取:
# access the mapped TableSomeClass.__table__# access the MapperSomeClass.__mapper__
例如:
from sqlalchemy import Column, Integer, Stringclass User(Base):     __tablename__ = 'users'      id = Column(Integer, primary_key=True)     name = Column(String(50))     fullname = Column(String(50))
password = Column(String(12))
  def __init__(self, name, fullname, password): self.name = name self.fullname = fullname self.password = password  def __repr__(self): return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)
注意,
            1> 在创建表之前要使用数据库。一 可以在create_engine的时候指定要连接的数据库;或者 二             
            session.execute('create database abc')            print session.execute('show databases').fetchall()            session.execute('use abc')     
                 这里,我使用方法二时,报错,创建了数据库abc,但是,abc中未创建表users。问题不是建表的代码,而是‘use abc’这句有问题,问题没有解决。我使用的方法一。
            2> 这里name = Column(String(50))需要指明string的长度,如果未指明,报错
映射类User:
    __tablename__:指明 真实数据库表的名字。
    Column函数:定义表列
映射表需要至少一个列被定义为主键列
不包含主键的数据库表可以被映射,如视图View
含复合多主键也支持映射。

构造函数__init__():提供基于为位置的参数访问
ed_user = User('ed', 'Ed Jones', 'edspassword')
若未自定义__init__()函数,则由于User继承自Base,所以Declarative系统会补一个,但是基于建的参数访问。
ed_user = User(name='ed', fullname='Ed Jones', password='foobar')
>>> User.__table__ Table('users', MetaData(None),    Column('id', Integer(), table=<users>, primary_key=True, nullable=False),    Column('name', String(), table=<users>),    Column('fullname', String(), table=<users>),    Column('password', String(), table=<users>), schema=None)
>>> User.__mapper__ <Mapper at 0x...; User>
同样的MetaData可以通过.metadata属性找到。

我们只定义了映射类User,数据库表user的创建,会由SQLAchemy完成。我们可以echo=true查看下
>>> Base.metadata.create_all(engine) PRAGMA table_info("users")()CREATE TABLE users (    id INTEGER NOT NULL,    name VARCHAR,    fullname VARCHAR,    password VARCHAR,    PRIMARY KEY (id))()COMMIT
Base.metadata.create_all(engine) :创建所有映射类对应的数据库表
Base.metadata.drop_all(engine):删除数据库及表

实例化映射类

>>> ed_user = User('ed', 'Ed Jones', 'edspassword')>>> ed_user.name'ed'>>> ed_user.password'edspassword'>>> str(ed_user.id)'None'
为什么id这个属性会为None值呢?
__init__()函数没有初始化id。所以默认会因为先前定义的ORM的id列(Column)而产生一个None值,在默认情况下,ORM会为所有被映射的表列创建类属性,这些属性是通过Python语言中描述符(Descriptors)机制来实现的。

SQLAlchemy 的连接创建是 Lazy 的方式其实我们现在并没有将数据插入数据库,一般主键会在插入数据库时自动产生一个不重复的值以保证唯一性。由于我们没有对对象实行持久化(Persist) (所谓的持久化就是把对象数据按照映射关系存储入数据库里) 所以这里id值为None。别着急,稍后当我们介绍将数据持久化后你就可以看到一个新的自动产生的id了。

4 创建并使用会话(Session)

We’re now ready to start talking to the database。ORM的操作句柄(Handle)被称为会话(Session)。

创建session

>>> from sqlalchemy.orm import sessionmaker>>> Session = sessionmaker(bind=engine)

Session = sessionmaker()# engine = create_engine(...) 创建引擎Session.configure(bind=engine,
                  autocommit=..,
                  expire_on_commit=..)  # 到这里engine应该已经创建

实例化Session类

>>> session = Session()
到这里session就获取了由Engine维护的数据库连接池,并且会维持内存中的映射数据直到提交(commit)更改或者关闭会话对象。



0 0
原创粉丝点击