推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
gkiwi
V2EX  ›  Python

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

  •  
  •   gkiwi · Aug 19, 2014 · 6409 views
    This topic created in 4313 days ago, the information mentioned may be changed or developed.
    酱紫:

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

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

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

    求靠谱方案,谢谢.

    sqlalchemy版本:0.9.7

    9 replies    2014-08-21 14:26:42 +08:00
    Zuckonit
        1
    Zuckonit  
       Aug 19, 2014
    xxx_A,xxx_B,xxx_C这个是表名?
    自定义__metaclass__

    ========================
    xxxAModel,xxxBModel,xxxCModel这个:
    xxxAModel = AModel
    xxxBModel = BModel
    xxxCModel = CModel
    beordle
        2
    beordle  
       Aug 19, 2014   ❤️ 1
    这样一定程度上能满足你的需求
    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
        3
    siteshen  
       Aug 19, 2014   ❤️ 1
    _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
        4
    siteshen  
       Aug 19, 2014   ❤️ 1
    上面是之前某次用的表明,除了增加 prefix 外,附加功能:CamelCase to under_score。
    gkiwi
        6
    gkiwi  
    OP
       Aug 19, 2014
    @Zuckonit
    @beordle

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

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

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

    @siteshen 的方法只是把BaseModel(BaseModel)增加了个动态属性啊 他下一句不是就是被继承了么?class UserToken(BaseModel) 为何说不能被继承呢
    gkiwi
        8
    gkiwi  
    OP
       Aug 20, 2014
    @beordle 我晓得你的意思,我也觉得这样子是合理的,但是用起来确实出现些问题,估计是我哪里写错了.以后有机会我再写个demo试试看.谢啦/
    siteshen
        9
    siteshen  
       Aug 21, 2014
    @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)
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   4114 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 63ms · UTC 05:17 · PVG 13:17 · LAX 22:17 · JFK 01:17
    ♥ Do have faith in what you're doing.