如何使用其他方法扩展SQLAlchemy绑定的声明式模型?

hll*_*lau 7 python orm sqlalchemy

例如,我在module上有一个声明式的类a

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    addresses = relationship("Address", backref="user")
Run Code Online (Sandbox Code Playgroud)

现在,在模块中,b我想使用映射的实体,但是添加一个方法:

from a import User

class UserWithExtraMethod(User):
    def name_capitalized(self):
        return self.name.capitalize()

user = UserWithExtraMethod()
print(user.name_capitalized)
Run Code Online (Sandbox Code Playgroud)

但是,当我运行脚本时,会出现以下错误:

InvalidRequestError: Multiple classes found for path "User" in the registry of this declarative base. Please use a fully module-qualified path.
Run Code Online (Sandbox Code Playgroud)

声明用户实体时我错过了什么?我想重用先前声明的实体。

我期望会是这样:

class UserWithExtraMethod(User):
    ___magic_reuse_previous_mapper__ = True

    def name_capitalized(self):
        return self.name.capitalize()
Run Code Online (Sandbox Code Playgroud)

Sin*_*ion 7

除非你有特殊原因需要单独的,否则你应该这样写:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    addresses = relationship("Address", backref="user")

    def name_capitalized(self):
        return self.name.capitalize()
Run Code Online (Sandbox Code Playgroud)

由于name_capitalized就 SQLAlchemy 而言并不特殊(它不是 aColumnExpression或类似的),因此映射器完全忽略它。

事实上,还有更好的方法来做到这一点;您的版本适用于 的实例User,但在 sql 表达式中没有用。

from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
class User(Base):
    # ... body as before

    @hybrid_method
    def name_capitalized(self):
        return self.name.capitalize()

    @name_capitalized.expression
    def name_capitalized(cls):
        # works for postgresql, other databases spell this differently.
        return sqlalchemy.func.initcap(cls.name)
Run Code Online (Sandbox Code Playgroud)

这将允许您执行以下操作:

>>> print Query(User).filter(User.name_capitalized() == "Alice")
SELECT users.id AS users_id, users.name AS users_name 
FROM users 
WHERE initcap(users.name) = :initcap_1
Run Code Online (Sandbox Code Playgroud)


van*_*van 1

Hacky,但是为什么不只是User为了您的目的而对类进行猴子修补,而不是继承它呢?

# modude b
from a import User

def name_capitalized(self):
    return self.name.capitalize()

User.name_capitalized = name_capitalized    
user = User() # and it has extra-method as well
print(user.name_capitalized)
Run Code Online (Sandbox Code Playgroud)