背景
话说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是一种流行的ORM(对象关系映射)工具,它在Python社区中被广泛使用,特别是在数据库操作和管理方面。ORM工具的主要目的是将数据库中的数据表结构映射到编程语言中的对象模型,允许开发者使用更加面向对象...
SQLAlchemy是一个功能强大的Python库,用于与关系型数据库进行交互,其最突出的特点是具有对象关系映射(ORM)功能。它提供了完善的工具集,让开发者能够以面向对象的方式操作数据库,而不是写原始SQL代码,极大地...
SQLAlchemy 是一个强大的 Python 数据库 ORM(对象关系映射)框架,它允许开发者使用面向对象的方式来操作数据库,而无需直接编写 SQL 语句。ORM 的核心思想是将数据库中的表映射为 Python 类,表中的行映射为类的...
**Flask-SQLAlchemy**是Python微框架Flask的一个扩展,它使得在Flask应用中集成和使用SQLAlchemy变得更加方便。SQLAlchemy是Python的一个强大的ORM(对象关系映射)库,能够将数据库操作转化为面向对象的编程方式。...
SQLAlchemy 是一个强大的 Python SQL 工具包和对象关系映射器,它为数据库操作提供了高级接口。在深入了解 SQLAlchemy 的核心概念之前,我们先来理解什么是 ORM(对象关系映射)。ORM 是一种技术,用于将数据库操作...