初始化时不能设置sqlalchemy hybrid_property,关键字参数无效?



我遇到了一个问题,我试图将字符串(以db为单位)转换为小数列表。

我的代码:'

@hybrid_property
def decimals(self) -> list[Decimal]:
return [Decimal(dec) for dec in self._decimals.replace('d', '').split(';')]

@decimals.setter
def decimals(self, decimals):
self._decimals = ';'.join(str(dec) for dec in decimals)

我得到一个错误'decimals'是一个无效的关键字参数

异常堆栈:

self = <app.models.models.Test_Db object at 0x000001F2A5EAA2F0>
kwargs = {'id': 0, 'connection': 'D', 'fron': 'loop feed', 'hasRail': False, ...}
cls_ = <class 'app.models.models.Test_Db'>, k = 'decimals'
def _declarative_constructor(self, **kwargs):
"""A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and
values in ``kwargs``.

Only keys that are present as
attributes of the instance's class are allowed. These could be,
for example, any mapped columns or relationships.
"""
cls_ = type(self)
for k in kwargs:
if not hasattr(cls_, k):
>               raise TypeError(
"%r is an invalid keyword argument for %s" % (k, cls_.__name__)
)
E               TypeError: 'decimals' is an invalid keyword argument for Test_Db
..envlibsite-packagessqlalchemyormdecl_base.py:1154: TypeError

您想要实现的功能类似于:

class Bar:
def __init__(self, _a):
self._a = _a
@property
def a(self):
return self._a
@a.setter
def a(self, a):
self._a = a
bar = Bar(a=1)  # TypeError: Bar.__init__() got an unexpected keyword argument 'a'

Bar__init__函数不知道a,只知道_a

当您试图用一个属性而不是映射属性__init__SQLAlchemy映射类时,也会发生同样的事情。

演示:

from decimal import Decimal
from sqlalchemy import Column, Integer, String, create_engine, select
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Session, declarative_base
Base = declarative_base()
class Foo(Base):
__tablename__ = "foo"
id = Column(Integer, primary_key=True)
_decimals = Column(String, nullable=False)
@hybrid_property
def decimals(self) -> list[Decimal]:
return [
Decimal(dec) for dec in self._decimals.replace("d", "").split(";")
]
@decimals.setter
def decimals(self, decimals: list[Decimal]) -> None:
self._decimals = ";".join(str(d) for d in decimals)

engine = create_engine("sqlite://", future=True, echo=True)
Base.metadata.create_all(engine)
with Session(bind=engine) as session:
session.add(Foo(_decimals="d1.0;d2.0;d3.0"))
session.commit()  # OK
with Session(bind=engine) as session:
session.add(Foo(decimals=[Decimal("4.0"),Decimal("5.0"),Decimal("6.0"))
session.commit()  # TypeError
with Session(bind=engine) as session:
result = session.scalars(select(Foo)).first()
print(result.decimals)  # [Decimal('1.0'), Decimal('2.0'), Decimal('3.0')]