2012-04-10 88 views
2

看看帖子的底部,你可以看到我有三个类。这里的代码是即时编写的伪代码,未经测试,但它充分显示了我的问题。如果我们需要实际的课程,我明天可以在工作时更新这个问题。因此,忽略语法问题和只代表思想的代码,而不是那些能够做我在那里描述的实际“代码”。sqlalchemy访问父类的属性

问题1 如果你看看Item搜索类的方法,你可以看到,当用户进行搜索时,我调用基类的搜索,然后基于该结果返回正确的类/对象。这工作,但似乎kludgy。有一个更好的方法吗?

问题2 如果你看看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

答1:其实你并不需要做什么特别的东西:给你正确地配置您的继承层次,您的查询就已经回到正确的类的每一行( ItemKitItem)。这是ORM部分的优点。什么,你可以,虽然做的是配置查询到immediatelly也将加载哪些不属于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),您必须自行决定。

+0

谢谢你的回答非常有帮助。当你说分析生成的SQL时,有一个问题是你打算打印声明并阅读它以确定它是我想要的还是你正在使用一个工具来帮助你进行分析? – Ominus 2012-04-11 02:04:52

+0

只需在引擎配置中通过设置#echo = True#启用SQL语句日志记录(http://docs.sqlalchemy.org/en/latest/core/engines.html?highlight=echo#engine-creation-api) – van 2012-04-11 06:58:52