背景
话说sqlalchemy真是一个非常好用的库,python orm基本上是舍我其谁了,文档还非常全面,基本上没有什么硬伤,现在也冲出了1.0版本,未来更加值得期待。
我最早用django orm,不过很快就觉得很多功能不够用,我当时用的版本是1.3.1,没有bulk insert也没有锁,没有这两个功能,好多应用就没法用django开发了。之后开始接触sqlalchemy,一直用到现在,总的体会是只有你想不到没有它做不到。
我们项目里有一个需求,就是数据按月分表,比如:2014年6月数据就存在record_201406表中, 其他月数据按此方法类推。这个需求如果是用sqlalchemy来获取数据,我们怎么做呢?
一般方法有什么问题?
一般情况下,我们很自然想到使用如下方法:
1 2 3 4 5 |
class RecodeDao_201406(Base): __tablename__ = 'record_201406' id = Column(INT(11), primary_key=True) ... |
或者简化点:
1 2 3 4 |
class RecodeDao_201406(Base): __table__ = Table('record_201406', Base.metadata, autoload=True) |
这样实现确实没问题,但回到需求上,既然是按月分表,难不成我要每个月写一个这样的model?每月上次线?当然不行,那我们怎么解决呢?
官网解决方法,有什么问题?
有经验的同学可能发现,这个不就是水平sharding么?这么说不完全对,看一下sharding的wiki定义:
A database shard is a horizontal partition of data in a database or search engine. Each individual partition is referred to as a shard or database shard. Each shard is held on a separate database server instance, to spread load.
我们这个需求只涉及单数据库,就不算sharding了,可以称为partitioning(分区),然而强大的sqlalchemy这两个情况都考虑到了,并且官网都提供了example,我们挑对应场景的partitioning出来看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class TBase(object): """Base class is a 'mixin'. Guidelines for declarative mixins is at: http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#mixin-classes """ id = Column(Integer, primary_key=True) data = Column(String(50)) def __repr__(self): return "%s(data=%r)" % ( self.__class__.__name__, self.data ) class T1Foo(TBase, Base): __tablename__ = 't1' class T2Foo(TBase, Base): __tablename__ = 't2' timestamp = Column(DateTime, default=func.now()) engine = create_engine('sqlite://', echo=True) Base.metadata.create_all(engine) sess = sessionmaker(engine)() sess.add_all([T1Foo(data='t1'), T1Foo(data='t2'), T2Foo(data='t3'), T1Foo(data='t4')]) print sess.query(T1Foo).all() print sess.query(T2Foo).all() |
使用了继承的方法,抽象的好,但我们之前的问题解决了吗?没有。还是需要预定义好所有表的model类,才能正确使用,迫不得已,我们只能自己想办法了。
函数方法解决
经过一番探索,我得出了如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class_registry = {} DbBase = declarative_base(bind=engine, class_registry=class_registry) def get_model(modelname, tablename, metadata=DbBase.metadata): """ args: modelname:新model名,string类型 tablename:数据库中表名 usage: RecordDao = get_model("RecordDao_201406", "record_201406") """ if modelname not in class_registry: model = type(modelname, (DbBase,), dict( __table__ = Table(tablename, metadata, autoload=True) )) else: model = class_registry[modelname] return model |
每次想获取对应月表数据的model,调用get_model方法即可。这个方法一直沿用到现在,虽然有点丑陋,但却是解决了以上问题。直到sqlalchemy 0.9.1版本推出Automap
Automap方法
sqlalchemy文档完备,具体可点击Automap,它可以自动映射数据库的表,通过数据表名映射model,简单直接,实现起来如下:
1 2 3 4 5 6 7 8 |
from sqlalchemy.ext.automap import automap_base AutoBase = automap_base() # reflect the tables AutoBase.prepare(engine, reflect=True) tablename = "record_201406" RecordDao = getattr(AutoBase.classes, tablename) |
这样就可以了,很清晰。但是这个方法有一个缺点,Automap的映射虽然是自动的,但是只有在启动的时候生效,也就是说如果新建一个数据表,而没有告诉Automap,那这个表是找不到的。在实际使用中,可以捕获AttributeError异常,并再次调用AutoBase.prepare(engine, reflect=True)
刷新映射关系。
相关推荐
sqlalchemy 文档 供大家参考
Python+MySQL分表分库实战. 值得收藏与下载哦....!!!!!!!!!!!!
SQLAlchemy是Python编程语言下的一款开源软件。提供了SQL工具包及对象关系映射(ORM)工具,使用MIT许可证发行。 SQLAlchemy“采用简单的Python语言,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型”...
Mysql 数据库 SQLAlchemy技术文档 SQLAlchemy技术文档(中文版)
SQLAlchemy 1.1 Documentation
Flask-SQLAlchemy包下载及安装,此类用于控制SQLAlchemy与一个或多个Flask应用程序的集成。 根据您初始化对象的方式,该对象立即可用或将根据需要附加到Flask应用程序。
SQLAlchemy python 开发SQL
主要为大家详细介绍了利用flask sqlalchemy实现分页效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
sqlalchemy-utils, Sqlalchemy的各种实用程序函数和数据类型 utils Sqlalchemy的各种实用程序函数,新数据类型和帮助器。资源文档文档问题跟踪程序代码
sqlalchemy文档资料翻译(part)大部分内容和框架
sqlAlchemy教程
sqlalchemy 是python对数据库操作一个库。里面集成了各种方法。有兴趣的可以看看
sqlalchemy官方文档0.9版 英文epub
sqlalchemy官方文档
sqlalchemy的使用举例源码小程序,可参考学习python中的sqlalchemy的使用方法。
SQLAlchemy最新权威详细教程