注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

snoopyxdy的博客

https://github.com/DoubleSpout

 
 
 

日志

 
 

SQLAlchemy学习教程(三)  

2014-08-08 15:59:54|  分类: python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本节将介绍使用orm进行数据的增删改查的例子
首先是对表和类的定义实例,

# -*- coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.orm import *
from datetime import datetime
import sys
reload(sys)
sys.setdefaultencoding('utf8')

metadata = MetaData()
__engine = create_engine('mysql://root:@192.168.150.3/test',convert_unicode=True, echo=True, encoding='UTF-8')

metadata.bind = __engine

product_table = Table(
    'product', metadata,
    Column('sku', String(20), primary_key=True),
    Column('msrp', Numeric))
class Product(object):
    def __init__(self, sku, msrp, summary=None):
        self.sku = sku
        self.msrp = msrp
        self.summary = summary
        self.categories = []
        self.prices = []
    def __repr__(self):
        return '<Product %s>' % self.sku
mapper(Product, product_table)

Session = sessionmaker(bind=engine, echo_uow=True)
session = Session()

p1 = Product('123', 11.22)
p2 = Product('456', 33.44)
session.add(p1)
session.add(p2)
session.flush()


1、mapper中使用 exclude_properties
#排除id列名
mapper(Region, region_table, exclude_properties=['id'])

2、使用properties让数据对象属性和表属性进行关联
mapper(Region, region_table, properties=dict(
   region_name=region_table.c.name,
   region_id=region_table.c.id))

3、子查询映射关联(一般用不到)

average_price = select(
 [func.avg(product_price_table.c.price)],
 product_price_table.c.sku==product_table.c.sku)\
 .as_scalar() \
 .label('average_price')
#打印语句
print average_price
(SELECT avg(product_price.price)
FROM product_price, product
WHERE product_price.sku = product.sku) AS average_price
#执行子查询
mapper(Product, product_table, properties=dict(
 average_price=column_property(average_price)))
p = session.query(Product).get('123')
print p.sku, p.msrp, p.average_price
#打印结果
123 12.34 12.34


4、延迟加载
比如数据库存储了BLOB类型的2进制文件,我们只是希望用到这个数据才去加载他,可以这样建立映射关系

product_table = Table(
'product', metadata,
Column('sku', String(20), primary_key=True),
Column('msrp', Numeric),
Column('image1', Binary),
Column('image2', Binary),
Column('image3', Binary))
mapper(Product, product_table, properties=dict(
image1=deferred(product_table.c.image, group='images'),
image2=deferred(product_table.c.image, group='images'),
image3=deferred(product_table.c.image, group='images')))


5、mapper方法的一些参数
entity_name=None,
always_refresh=False,每次从数据库的查询到的数据都会重写内存数据,所以使用populate_existing()会优于这个参数。
allow_column_override=False,允许关联的属性和列名相同,这样列名就不会被映射了
allow_null_pks=False,允许主键为NULL,如果不设置,当主键为NULL时将不会跳过结构对象生成
batch=True,允许多个对象批处理save操作,如果设置为False,每个对象将会依次入库
column_prefix= None,自动加上映射列名属性的前缀
concrete=False,如果为true,说明使用的具体表继承
extension=None,一个映射的扩展对象或者映射扩展对象数组
inherits=None,另外一个映射对象,用来被继承的
inherit_condition=None,另外一个映射对象,继承的方式
inherit_foreign_keys=None,继承方式的参数
order_by=None,默认的排序方式对这个映射关系查询出的结果
non_primary=False,设定这个是不设置主键的映射
properties=None,一个字段,表示那些属性映射到表中,(不设置将会自动映射)
include_properties=None,一个属性数组,表示哪些属性会映射到表中,没有在数组中出现的属性不会映射到表中
exclude_properties=None,一个属性数组,那些属性确定不包括在数组中
primary_key=None,主键数组
polymorphic_on=None,
polymorphic_identity=None,
polymorphic_fetch='union',
select_table=None,
version_id_col=None

6、在映射中声明关系
一般关系对应有3种方式,1对多,多对多,1对1.
6.1、1对多的关系声明

mapper(Store, store_table)
mapper(Region, region_table, properties=dict(
   stores=relation(Store)))
mapper(Region, region_table, properties=dict(
#当两张表有多个外键关系时,SQLAlchemy无法判断用哪个作为外键,可以指定它
stores=relation(Store,
primaryjoin=(store_table.c.region_id==region_table.c.id))))


6.2、多对多的关系声明
定义两张多对多的表和一张关系关联表

category_table = Table(
'category', metadata,
Column('id', Integer, primary_key=True),
Column('level_id', None, ForeignKey('level.id')),
Column('parent_id', None, ForeignKey('category.id')),
Column('name', String(20)))

product_table = Table(
'product', metadata,
Column('sku', String(20), primary_key=True),
Column('msrp', Numeric))

product_category_table = Table(
'product_category', metadata,
Column('product_id', None, ForeignKey('product.sku'),
 primary_key=True),
Column('category_id', None, ForeignKey('category.id'),
 primary_key=True))

#定义mapper关系
mapper(Category, category_table, properties=dict(
 products=relation(Product,
 secondary=product_category_table)))

#另外一个关系映射也要声明一下

mapper(Product, product_table, properties=dict(
 categories=relation(Category,
 secondary=product_category_table)))


6.3、1对1的关系
1对1是特殊的1对多关系,只需要这样声明即可

mapper(Product, product_table, properties=dict(
 summary=relation(ProductSummary, uselist=False)))


7、backref避免重复两次声明关系

mapper(Level, level_table, properties=dict(
 categories=relation(Category, backref='level')))

mapper(Category, category_table, properties=dict(
 products=relation(Product, secondary=product_category_table,
 backref='categories')))

#同样可以使用backref()方法来建立另外一个1对1的关系

mapper(ProductSummary, product_summary_table, properties=dict(
   product=relation(Product,
   backref=backref('summary', uselist=False))))

mapper(Product, product_table)


8、relation函数的参数
backref(relation( )only),反向的关系自动声明
cascade,层叠改变关系,主要用于1对多,当parent改变,Children也会改变,参数是all,delete,save-update,refresh- expire,merge,expunge,delete-orphan
collection_class,
foreign_keys,外键申明数组
join_depth=None,连接深度
lazy=True,
order_by,排序
passive_deletes=False,如果为true,表示自动删除子关联,当主键为null或者父删除
post_update=False,如果设置为true,SQLAlchemy会分开CRUD操作,否则将会把CRUD操作放在一个声明里
primaryjoin,设定怎么连接父表和子表
remote_side,用于本表关联
secondary,在多对多关系中,用来声明关系表
secondaryjoin,多对多关系,声明父表如何链接关系表
uselist=True,1对1关系时声明
viewonly=False,只读操作连接

9、步入正轨,使用ORM进行查询和修改
两种方式生成session
 第一种方式

Session = sessionmaker(bind=engine)

 第二种方式

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

sessionmaker接受参数:
bind=None,参数是一个数据库引擎或者连接字符串
binds=None,绑定其他mapper对象或者表
autoflush=True,自动flush
transactional=False,事物操作,当设置为true时,无需使用begin( )来声明事物开始,只需要执行commit()就可以提交事物,回滚使用rollback()
twophase=False,多数据库事物支持回滚
echo_uow=False,输出debug信息
extension=None,扩展字段
weak_identity_map=True,自动回收,如果设置为false,需要手动执行session的expunge( ), clear( ), or purge( )进行回收

10、将数据对象保存到session中

product_table = Table(
    'product', metadata,
    Column('sku', String(20), primary_key=True),
    Column('msrp', Numeric))

class Product(object):
    def __init__(self, sku, msrp, summary=None):
        self.sku = sku
        self.msrp = msrp
        self.summary = summary
        self.categories = []
        self.prices = []
    def __repr__(self):
        return '<Product %s>' % self.sku

mapper(Product, product_table)

Session = sessionmaker(bind=engine, echo_uow=True)
session = Session()
p1 = Product('123', 11.22)
p2 = Product('456', 33.44)
session.add(p1)
session.add(p2)
session.flush()


11、从session中删除

session.delete(p1)


12、事物的操作

session.begin()
session.commit()
session.rollback()


13、其他session方法

save( self, obj, entity=None),
delete( self, obj ),从下次flush中,删除对象
expire( self, obj ),
refresh( self, obj )
merge( self, obj, entity=None )
expunge( self, obj ),在session中删除整个对这个对象的引用
update( self, obj, entity=None ),
get( self, class_, ident, **kwargs ),
load( self, class_, ident, **kwargs )
query( self, mapper_or_class, *addtl_entities, **kwargs ),查询
clsoe(),摧毁这个session
execute( self, clause, params=None, mapper=None, **kwargs ),
identity_map
new
dirty
deleted


14、session查询的例子,只有当执行all等操作时,才回去数据库真正的执行操作

query = session.query(Product)
query = query.filter_by(msrp=11.22)
query = query.limit(3)
print query.all() #.first()


15、多表orm联查

query = session.query(Product)
query = query.join('categories')
query = query.filter_by(name='T-Shirts')
print query.all()
[<Product 222>]
print query
SELECT product.sku AS product_sku, product.msrp AS product_msrp
FROM product JOIN product_category ON product.sku =
 product_category.product_id JOIN category ON category.id =
 product_category.category_id
WHERE category.name = ? ORDER BY product.oid
join方法是inner join,outjoin则是outerjoin
#filter方法实例
 query = query.filter(or_(Category.c.name=='Pants',
   Category.c.name==None))


16、from_statement,从select语句中获取查询条件

 session.clear()
 stmt = select([product_table.c.sku])
 query = session.query(Product).from_statement(stmt)
 for prod in query:
    print prod, prod.msrp


17、query对象的一些方法:
add_column( self, column, id=None ),对当前查询对象增加一列
add_entity( self, entity, alias=None, id=None ),对当前查询对象增加一个实体
all( self ),去数据库执行查询操作,然会resultProxy类型
autoflush( self, setting ),自动刷数据库
apply_avg( self, col ),增加SQL AVG,返回query对象
apply_max( self, col ),增加SQL MAX,返回query对象
apply_min( self, col ),增加SQL MIN,返回query对象
apply_sum( self, col ),增加SQL SUM,返回query对象
avg( self, col ),增加SQL avg,去数据库查询
count( self ),去数据库查询,并返回计数
distinct( self ),对整个query对象增加去重复,返回query
filter( self, criterion ),增加过滤对象,返回query
filter_by( self, **kwargs ),增加过滤字典,返回query
first( self ),去数据库返回查询结果的一条
from_statement( self, statement ),传入使用select()函数生成的查询语句,返回query
get( self, ident, reload=False, lockmode=None ),检查当前session是否具有此对象,如果有则
group_by( self, criterion ),分组,返回query
having( self, criterion ),增加having条件,返回query
join( self, prop, id=None, aliased=False, from_joinpoint=False ),新增加一个表,进行from查询,返回query
limit( self, limit ),limit限制,返回query
load( self, ident, raiseerr=True, lockmode=None ),从数据库返回这个实例
max( self, col ),执行SQL MAX
min( self, col, ),执行SQL MIN
offset( self, offset ),偏移量,返回query
one( self ),执行sql,返回结果,如果结果不是一个则抛出异常
options( self, *args ),根据数据中的mapper,返回一个新的query
order_by( self, criterion ),排序,返回query,
outerjoin( self, prop, id=None, aliased=False, from_joinpoint=False ),外联操作,返回query
params( self, *args, **kwargs ),更改现有的query中的查询绑定的值,返回query
populate_existing( self ),返回一个query,刷新所有对象
query_from_parent( cls, instance, property, **kwargs ) (classmethod),从另外一个query继承
reset_joinpoint( self ),重置连接属性,会影响filter_by,join,outerjoin
sum( self, col ),执行sum
with_lockmode( self, mode ),返回query,设置lockmodle
with_parent( self, instance, property=None ),从父query继承
__getitem__( self, item ) (indexing)
__iter__( self ) (iteration)

18、使用一个上下文线程session,tornado的例子

Session = scoped_session(sessionmaker(
 bind=engine, autoflush=True, transactional=True))
session = Session()
session2 = Session()
session is session2
#用完需要调用close来清理

  评论这张
 
阅读(2163)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016