如何为 sqlalchemy 统一加表明前缀?

2014-08-19 11:57:40 +08:00
 gkiwi
酱紫:

原先有表A,B,C等.也已经做好了AModel,BModel,CModel.
现在因为需求原因(合并库),需要在A,B,C前面加前缀xxx,变成:
xxx_A,xxx_B,xxx_C
xxxAModel,xxxBModel,xxxCModel

当然手动一个个改也可以,只是一个比较麻烦,二是调用时候,xxxAModel调用也会很难看.请问有啥解决方案没?

网上搜到几个,但是不解决问题.

求靠谱方案,谢谢.

sqlalchemy版本:0.9.7

5921 次点击
所在节点    Python
9 条回复
Zuckonit
2014-08-19 13:09:54 +08:00
xxx_A,xxx_B,xxx_C这个是表名?
自定义__metaclass__

========================
xxxAModel,xxxBModel,xxxCModel这个:
xxxAModel = AModel
xxxBModel = BModel
xxxCModel = CModel
beordle
2014-08-19 13:42:55 +08:00
这样一定程度上能满足你的需求
class Class(db.Model):
__tablename__ = 'wl_class'
id = db.Column('class_id', db.Integer, primary_key=True)
name = db.Column('class_name', db.String(45), nullable=False, unique=True)
products = db.relationship('Product', backref='wl_class', lazy='dynamic')

def as_dict(self):
return dict([(c, getattr(self, c)) for c in self.__dict__ if c in ('name', 'products')])
我是觉得这样很方便,__metaclass__应该也可以, 但是注意一旦要用__new__, 因为我觉得__ init__ 的调用时机可能不一定可以
siteshen
2014-08-19 14:30:47 +08:00
_table_prefix = 'v1_'

class BaseModel(BaseModel):
@declared_attr
def __tablename__(cls):
# simple CamelCase to under_score
name = ''.join([('_' + ch.lower()) if ch.isupper() else ch
for ch in cls.__name__]).strip('_')
return _table_prefix + name

__abstract__ = True
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}

# tablename: v1_user_token
class UserToken(BaseModel):
id = Column(INTEGER(unsigned=True), primary_key=True)
siteshen
2014-08-19 14:32:49 +08:00
上面是之前某次用的表明,除了增加 prefix 外,附加功能:CamelCase to under_score。
bcxx
2014-08-19 14:40:48 +08:00
gkiwi
2014-08-19 21:26:04 +08:00
@Zuckonit
@beordle

两位的应该都无法解决这个问题(或者是我没看懂).

@siteshen 这个方法确实能够解决问题,而且__tablename__上面用装饰器也是我之前从未考虑过得.这样子统一引用_table_prefix也能够很方便的更改.但是其亮点也是其劣势,这样子的__tablename__意味着我需要拷贝多份(似乎BaseModel不能够被继承使用,之前我使用出过问题,最后只能用多继承来实现部分常用方法.但是这块我觉得也有可能是我的用法不对.)

@bcxx 这个也是我在网上找到的一个解决方案,也是我最喜欢的.可惜用的时候不晓得哪里出错了.打算写个demo测试下.
beordle
2014-08-19 22:27:27 +08:00
@gkiwi

@siteshen 的方法只是把BaseModel(BaseModel)增加了个动态属性啊 他下一句不是就是被继承了么?class UserToken(BaseModel) 为何说不能被继承呢
gkiwi
2014-08-20 10:27:50 +08:00
@beordle 我晓得你的意思,我也觉得这样子是合理的,但是用起来确实出现些问题,估计是我哪里写错了.以后有机会我再写个demo试试看.谢啦/
siteshen
2014-08-21 14:26:42 +08:00
@beordle
@gkiwi 的意思应该是要用继承的方式使用公共字段。这个需要特殊处理,告诉SQLAlchemy建立多个Column。摘取部分代码如下(至于declared_attr的意思,你可以去看看文档,我也不太清楚):
http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html#mixing-in-columns

from sqlalchemy.ext.declarative import declared_attr

class ReferenceAddressMixin(object):
@declared_attr
def address_id(cls):
return Column(Integer, ForeignKey('address.id'))

class User(ReferenceAddressMixin, Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/128704

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX