Skip to main content
 首页 » 编程设计

python之sqlalchemy访问父类属性

2025年05月04日14think

查看帖子底部,您可以看到我有三个类(class)。这里的代码是动态编写的伪代码,未经测试,但它充分说明了我的问题。如果我们需要实际的类(class),我可以在明天上类时更新这个问题。因此,请忽略语法问题和仅代表思想的代码,而不是可以执行我在那里描述的实际“代码”。

问题一 如果您查看 Item 搜索类方法,您会发现当用户进行搜索时,我会在基类上调用搜索,然后根据该结果返回正确的类/对象。这有效但看起来很笨拙。有更好的方法吗?

问题二 如果您查看 KitItem 类,您会发现我正在覆盖标价。如果标志 calc_list 设置为 true,那么我将组件的标价相加并将其作为套件的标价返回。如果它没有标记为真,我想返回“基本”标价。然而,据我所知,没有办法访问父属性,因为在正常设置中它是没有意义的,但对于 sqlalchemy 和共享表继承它可能很有用。

TIA

class Item(DeclarativeBase): 
    __tablename__ = 'items' 
    item_id = Column(Integer,primary_key=True,autoincrement=True) 
    sku = Column(Unicode(50),nullable=False,unique=True) 
    list_price = Column(Float) 
    cost_price = Column(Float) 
    item_type = Column(Unicode(1)) 
    __mapper_args__ = {'polymorphic_on': item_type} 
    __ 
    def __init__(self,sku,list_price,cost_price): 
        self.sku = sku 
        self.list_price = list_price 
        self.cost_price = cost_price 
 
    @classmethod 
    def search(cls): 
        """ 
        " search based on sku, description, long description 
        " return item as proper class 
        """ 
        item = DBSession.query(cls).filter(...) #do search stuff here 
        if item.item_type == 'K': #Better way to do this??? 
            return DBSession.query(KitItem).get(item.item_id) 
 
class KitItem(Item): 
    __mapper_args__ = {'polymorphic_identity': 'K'} 
    calc_list = Column(Boolean,nullable=False,default=False) 
 
    @property 
    def list_price(self): 
        if self.calc_list: 
            list_price = 0.0 
            for comp in self.components: 
                list_price += comp.component.list_price * comp.qty 
            return list_price 
        else: 
            #need help here 
            item = DBSession.query(Item).get(self.item_id) 
            return item.list_price 
 
class KitComponent(DeclarativeBase): 
    __tablename__ = "kit_components" 
    kit_id = Column(Integer,ForeignKey('items.item_id'),primarykey=True) 
    component_id = Column(Integer,ForeignKey('items.item_id'),primarykey=True) 
    qty = Column(Integer,nullable=False, default=1) 
    kit = relation(KitItem,backref=backref("components")) 
    component = relation(Item) 

请您参考如下方法:

答案 1: 事实上,您不需要在这里做任何特别的事情:假设您正确配置了继承层次结构,您的查询将已经为每一行返回正确的类(Item 或 KitItem)。这是ORM部分的优势。不过,您可以做的是将查询配置为立即加载属于 Item 子项的其他列(从您的代码来看,这只是 calc_list 列),这您可以通过指定 with_polymorphic('*') 来完成:

@classmethod 
def search(cls): 
    item = DBSession.query(cls).with_polymorphic('*').filter(...) #do search stuff here 
    return item 

在 Basic Control of Which Tables are Queried 中阅读更多相关信息.
要查看差异,启用 SQL 日志记录,并比较使用和不使用 with_polymorphic(...) 的测试脚本 - 您很可能需要执行更少的 SQL 语句。

答案 2: 我不会用纯计算的条目覆盖一个条目。相反,我会创建另一个计算属性(我们称之为 final_price),对于两个类中的每一个,它看起来如下所示:

class Item(Base): 
    ... 
    @property 
    def total_price(self): 
        return self.list_price 
 
class KitItem(Item): 
    ... 
    @property 
    def total_price(self): 
        if self.calc_list: 
            _price = 0.0 
            for comp in self.components: 
                _price += comp.component.list_price * comp.qty 
            return _price 
        else: 
            # @note: again, you do not need to perform any query here at all, as *self* is that you need 
            return self.list_price 

同样在这种情况下,您可能会想到配置关系 KitItem.components 以预先加载,这样 total_price 的计算就不会触发额外的 SQL。但是您必须自己决定这是否对您的用例有益(同样,分析在您的场景中生成的 SQL)。