result=statement.execute() #检索所有在2007年创建的用户
metadata=MetaData(‘sqlite:
//’)#告诉它你设置的数据库类型是基于内存的sqlite
user_table=Table( #创建一个表
‘tf_user’,metadata,
Column(‘id’,Integer,primary_key=True), #一些字段,假设你懂SQL,那么以下的字段很好理解
Column(‘user_name’,Unicode(16),unique=True,nullable=False),
Column(‘email_address’,Unicode(255),unique=True,nullable=False),
Column(‘password’,Unicode(40),nullable=False),
Column(‘first_name’,Unicode(255),default=”),
Column(‘last_name’,Unicode(255),default=”),
Column(‘created’,DateTime,default=datetime.now))
users_table=Table(‘users’,metadata,autoload=True)#假设table已经存在.就不需要指定字段,只是加个autoload=True
classUser(object):
pass #虽然SQLAlchemy强大,但是插入更新还是需要手动指定,可以使用ORM,方法就是:
设定一个类,定义一个表,把表映射到类里面
mapper(User,user_table)
下面是一个完整ORM的例子:
Sourcecode
fromsqlalchemy.ormimportmapper,sessionmaker#sessionmaker()函数是最常使用的创建最顶层可用于整个应用Session的方法,Session管理着所有与数据库之间的会话
fromdatetimeimportdatetime
fromsqlalchemyimportTable,MetaData,Column,ForeignKey,Integer,String,Unicode,DateTime#会SQL的人能理解这些函数吧?
engine=create_engine("sqlite:
///tutorial.db",echo=True)#创建到数据库的连接,echo=True表示用logging输出调试结果
metadata=MetaData()#跟踪表属性
user_table=Table(#创建一个表所需的信息:
字段,表名等
'tf_user',metadata,
Column('id',Integer,primary_key=True),
Column('user_name',Unicode(16),unique=True,nullable=False),
Column('email_address',Unicode(255),unique=True,nullable=False),
Column('password',Unicode(40),nullable=False),
Column('first_name',Unicode(255),default=''),
Column('last_name',Unicode(255),default=''),
Column('created',DateTime,default=datetime.now))
metadata.create_all(engine)#在数据库中生成表
classUser(object):
pass#创建一个映射类
mapper(User,user_table)#把表映射到类
Session=sessionmaker()#创建了一个自定义了的Session类
Session.configure(bind=engine)#将创建的数据库连接关联到这个session
session=Session()
u=User()
u.user_name='dongwm'
u.email_address='dongwm@'
u.password='testpass'#给映射类添加以下必要的属性,因为上面创建表指定这几个字段不能为空
session.add(u)#在session中添加内容
session.flush()#保存数据
mit()#数据库事务的提交,sisson自动过期而不需要关闭
query=session.query(User)#query()简单的理解就是select()的支持ORM的替代方法,可以接受任意组合的class/column表达式
printlist(query)#列出所有user
printquery.get
(1)#根据主键显示
printquery.filter_by(user_name='dongwm').first()#类似于SQL的where,打印其中的第一个
u=query.filter_by(user_name='dongwm').first()
u.password='newpass'#修改其密码字段
mit()#提交事务
printquery.get
(1).password#打印会出现新密码
forinstanceinsession.query(User).order_by(User.id):
#根据id字段排序,打印其中的用户名和邮箱地址
printinstance.user_name,instance.email_address
既然是ORM框架,我们来一个更复杂的包含关系的例子,先看sql语句:
CREATETABLEtf_user(
idINTEGERNOTNULL,
user_nameVARCHAR(16)NOTNULL,
email_addressVARCHAR(255)NOTNULL,
passwordVARCHAR(40)NOTNULL,
first_nameVARCHAR(255),
last_nameVARCHAR(255),
createdTIMESTAMP,
PRIMARYKEY(id),
UNIQUE(user_name),
UNIQUE(email_address));
CREATETABLEtf_group(
idINTEGERNOTNULL,
group_nameVARCHAR(16)NOTNULL,
PRIMARYKEY(id),
UNIQUE(group_name));
CREATETABLEtf_permission(
idINTEGERNOTNULL,
permission_nameVARCHAR(16)NOTNULL,
PRIMARYKEY(id),
UNIQUE(permission_name));
CREATETABLEuser_group(
user_idINTEGER,
group_idINTEGER,
PRIMARYKEY(user_id,group_id),
FOREIGNKEY(user_id)REFERENCEStf_user(id),#user_group的user_id关联了tf_user的id字段
FOREIGNKEY(group_id)REFERENCEStf_group(id)); #group_id关联了tf_group的id字段
CREATETABLEgroup_permission(
group_idINTEGER,
permission_idINTEGER,
PRIMARYKEY(group_id,permission_id),
FOREIGNKEY(group_id)REFERENCEStf_group(id), #group_permission的id关联tf_group的id字段
FOREIGNKEY(permission_id)REFERENCEStf_permission(id));#permission_id关联了tf_permission的id字段
这是一个复杂的多对多的关系,比如检查用户是否有admin权限,sql需要这样:
SELECTCOUNT(*)FROMtf_user,tf_group,tf_permissionWHERE
tf_user.user_name=’dongwm’ANDtf_user.id=user_group.user_id
ANDuser_group.group_id=group_permission.group_id
ANDgroup_permission.permission_id=tf_permission.id
ANDpermission_name=’admin’; 看起来太复杂并且繁长了
在面向对象的世界里,是这样的:
classUser(object):
groups=[]
classGroup(object):
users=[]
permissions=[]
classPermission(object):
groups=[]
Sourcecode
print'Summaryfor%s'%user.user_name
forginuser.groups:
print'Memberofgroup%s'%g.group_name
forping.permissions:
print'...whichhaspermission%s'%p.permission_name
Sourcecode
defuser_has_permission(user,permission_name):
#检查用户是否有permission_name的权限的函数
forginuser.groups:
forping.permissions:
#可以看出来使用了for循环
ifp.permission_name=='admin':
returnTrue
returnFalse
而在SQLAlchemy中,这样做:
mapper(User,user_table,properties=dict(
groups=relation(Group,secondary=user_group,backref=’users’)))#properties是一个字典值。
增加了一个groups值,它又是一个relation对象,这个对象实现
#了Group类与user_group的 映射。
这样我通过user_table的groups属性就可以反映出RssFeed的值来,
#中间表对象(user_group)传给secondary参数,backref为自己的表(users)
mapper(Group,group_table,properties=dict(
permissions=relation(Permission,secondary=group_permission,
backref=’groups’)))
mapper(Permission,permission_table)
q=session.query(Permission)
dongwm_is_admin=q.count_by(permission_name=’admin’,user_name=’dongwm’)
假如计算组里用户数(不包含忘记删除但是重复的)
forpinpermissions:
users=set()
forginp.groups:
foruing.users:
users.add(u)
print‘Permission%shas%dusers’%(p.permission_name,len(users))
在SQLAlchemy可以这样:
q=select([Permission.c.permission_name,
func.count(user_group.c.user_id)],
and_(Permission.c.id==group_permission.c.permission_id,
Group.c.id==group_permission.c.group_id,
Group.c.id==user_group.c.group_id),
group_by=[Permission.c.permission_name],
distinct=True)
rs=q.execute()
forpermission_name,num_usersinq.execute():
print‘Permission%shas%dusers’%(permission_name,num_users)#虽然也长,但是减少了数据库查询次数,也就是让简单事情简单化,复杂事情可能简单解决
看一个综合的例子:
classUser(object):
#这些类设计数据库的模型
def__init__(self,group_name=None,users=None,permissions=None):
ifusersisNone:
users=[]
ifpermissionsisNone:
permissions=[]
self.group_name=group_name
self._users=users
self._permissions=permissions
defadd_user(self,user):
self._users.append(user)
defdel_user(self,user):
self._users.remove(user)
defadd_permission(self,permission):
self._permissions.append(permission)
defdel_permission(self,permission):
self._permissions.remove(permission)
classPermission(object):
def__init__(self,permission_name=None,groups=None):
self.permission_name=permission_name
self._groups=groups
defjoin_group(self,group):
self._groups.append(group)
defleave_group(self,group):
self._groups.remove(group)
用sqlalchemy的效果是这样的:
user_table=Table(
‘tf_user’,metadata,
Column(‘id’,Integer,primary_key=True),
Column(‘user_name’,Unicode(16),unique=True,nullable=False),
Column(‘password’,Unicode(40),nullable=False))
group_table=Table(
‘tf_group’,metadata,
Column(‘id’,Integer,primary_key=True),
Column(‘group_name’,Unicode(16),unique=True,nullable=False))
permission_table=Table(
‘tf_permission’,metadata,
Column(‘id’,Integer,primary_key=True),
Column(‘permission_name’,Unicode(16),unique=True,
nullable=False))
user_group=Table(
‘user_group’, metadata,
Column(‘user_id’,None,ForeignKey(‘tf_user.id’),
primary_key=True),
Column(‘group_id’,None,ForeignKey(‘tf_group.id’),
primary_key=True))
group_permission=Table(
‘group_permission’, metadata,
Column(‘group_id’,None,ForeignKey(‘tf_group.id’),
primary_key=True),
Column(‘permission_id’,None,ForeignKey(‘tf_permission.id’),
primary_key=True))
mapper(User,user_table,properties=dict(
_groups=relation(Group,secondary=user_group,backref=’_users’)))
mapper(Group,group_table,properties=dict(
_permissions=relation(Permission,secondary=group_permission,
backref=_’groups’)))
mapper(Permission,permission_table)
这里没有修改对象,而join_group,leave_group这样的函数依然可用,sqlalchemy会跟踪变化,并且自动刷新数据库
上面介绍了一个完整的例子,连接数据库嗨可以这样:
engine=create_engine(‘sqlite:
//’)
connection=engine.connect() #使用connect
result=connection.execute(“selectuser_namefromtf_user”)
forrowinresult:
print‘username:
%s’%row['user_name']
result.close()
engine=create_engine(‘sqlite:
//’,strategy=’threadlocal’) #,strategy=’threadlocal’表示重用其它本地线程减少对数据库的访问
fromsqlalchemy.databases.mysqlimportMSEnum,MSBigInteger #这个sqlalchemy.databases是某数据库软件的’方言’集合,只支持特定平台
user_table=Table(‘tf_user’,meta,
Column(‘id’,MSBigInteger),
Column(‘honorific’,MSEnum(‘Mr’,‘Mrs’,‘Ms’,‘Miss’,‘Dr’,‘Prof’)))
以下是几个MetaData的应用:
unbound_meta=MetaData() #这个metadata没有绑定
db1=create_engine(‘sqlite:
//’)
unbound_meta.bind=db1 #关联引擎
db2=MetaData(‘sqlite:
///test1.db’) #直接设置引擎
bound_meta1=MetaData(db2)
#CreateaboundMetaDatawithanimplicitlycreatedengine
bound_meta2=MetaData(‘sqlite:
///test2.db’) #隐式绑定引擎
meta=MetaData(‘sqlite:
//’)#直接绑定引擎可以让源数据直接访问数据库
user_table=Table(
‘tf_user’,meta,
Column(‘id’,Integer,primary_key=True),
Column(‘user_name’,Unicode(16),unique=True,nullable=False),
Column(‘password’,Unicode(40),nullable=False))