该应用程序具有这样的逻辑:存储在数据库中的人员列表,每个人都有一个实时计算的评分,这个值永远不会存储在数据库中。我想使用一个类来处理 dababase 字段:姓名、年龄等和非数据库字段:评级。
在 sqlalchemy 中可能吗?现在我使用继承 Man -> ManMapping:
class Man:
rating = None
def get_rating(self):
return self.rating
...
class ManMapping(Base, Man):
__tablename__ = 'man'
id = Column('man_id', Integer, primary_key=True)
name = Column(Unicode)
...
Run Code Online (Sandbox Code Playgroud)
它有效,但对我来说看起来很糟糕。这是正确的方法还是我必须做其他事情?
这是正确的解决方案:https://docs.sqlalchemy.org/en/13/orm/constructors.html \n混合属性的灵活性比这要差一些。接受的答案并不是问题的实际答案。
\n\n\n从数据库行重新创建对象时,SQLAlchemy ORM 不会调用init 。ORM\xe2\x80\x99s 过程有点类似于 Python 标准库\xe2\x80\x99s pickle 模块,调用低级new方法,然后直接在实例上悄悄恢复属性,而不是调用init。
\n
\n\n如果您需要在数据库加载的实例\xe2\x80\x99 准备使用之前对其进行一些设置,可以使用名为 InstanceEvents.load() 的事件挂钩来实现此目的;它也可以通过称为reconstructor()的特定于类的装饰器来使用。当使用reconstructor()时,映射器将在每次加载或重建类的实例时调用不带参数的修饰方法。这对于重新创建通常在init中分配的瞬态属性非常有用:
\n
from sqlalchemy import orm\n\nclass MyMappedClass(object):\n def __init__(self, data):\n self.data = data\n # we need stuff on all instances, but not in the database.\n self.stuff = []\n\n @orm.reconstructor\n def init_on_load(self):\n self.stuff = []\nRun Code Online (Sandbox Code Playgroud)\n
在我看来,你应该有两个不同的类。一种用于代码中的逻辑,另一种用于与数据库通信。
class Man(object):
"""This class is for your application"""
def __init__(self, name, rating):
# If the identifier is only used by the DB it should not be in this class
self.name = name
self.rating = rating
class ManModel(Base):
"""This model is only to communicate with the DB"""
__tablename__ = 'man'
id = Column('man_id', Integer, primary_key=True)
name = Column(Unicode)
Run Code Online (Sandbox Code Playgroud)
您应该有一个提供程序,它使用ManModel对象对数据库进行查询,然后将结果映射到Man对象并将映射的数据返回给调用者。您的应用程序将仅使用Man对象,并且您的提供者将进行映射。像下面这样:
class DbProvider(object):
def get_man(self, id):
man_model = session.query(ManModel).filter(ManModel.id == id).one_or_none()
return self.man_mapper(man_model) if man_model else None
def get_men(self):
men_model = session.query(ManModel).all()
return [self.man_mapper(man_model) for man_model in men_model]
def man_mapper(self, man_model):
return Man(man_model.name, self.calculate_rating(man_model))
class Test(object):
def display_man(self):
man = db_provider.get_man(15)
if man:
print man.name, man.rating
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4108 次 |
| 最近记录: |