2014-10-23 1 views
1

У меня есть 4 таблицы: Гибридный выражение, которое подсчитывает число строк с условием

class Cebola(Base): 
    __tablename__ = 'cebolas' 
    id = Column(Integer, primary_key=True, autoincrement=True) 


class Checklist(Base): 
    __tablename__ = 'checklists' 

    id = Column(Integer, primary_key=True, autoincrement=True) 
    checklist_type = Column(String) 
    cebola_id = Column(Integer, ForeignKey('cebolas.id')) 
    cebola = relationship('Cebola', backref=backref('checklists')) 

    __mapper_args__ = {'polymorphic_on': checklist_type, 
         'polymorphic_identity': 'generic'} 


class ChecklistA(Checklist): 
    __tablename__ = 'checklist_a' 

    id = Column(Integer, ForeignKey('checklists.id', ondelete='CASCADE'), primary_key=True) 
    notes = Column(Unicode) 

    __mapper_args__ = {'polymorphic_identity': 'a'} 


class ChecklistB(Checklist): 
    __tablename__ = 'checklist_b' 

    id = Column(Integer, ForeignKey('checklists.id', ondelete='CASCADE'), primary_key=True) 
    notes = Column(Unicode) 

    __mapper_args__ = {'polymorphic_identity': 'b'} 

Теперь мне нужен способ (возможно, гибридная собственность), который скажет мне, сколько контрольных списков я имею в Cebola с notes <> ''.

Я добавил:

class Cebola(Base): 

    @hybrid_property 
    def number_of_comments(self): 
     return len([c for c in self.checklists if c.notes]) 

    @number_of_comments(cls) 
    def number_of_comments(cls): 
     ??? 

я нашел подобную проблему в SQLAlchemy - Writing a hybrid method for child count, но мой пример немного сложнее.

+0

А как бы вы хотели, чтобы обрабатывать 'Checklist' родовые экземпляры, которые не имеют' notes' собственности? – van

+0

@van они могут быть проигнорированы – amleczko

ответ

1

Ниже вы должны получить начал:

class Cebola(Base): 
    __tablename__ = 'cebolas' 
    id = Column(Integer, primary_key=True, autoincrement=True) 

    @hybrid_property 
    def number_of_comments(self): 
     # return len([c for c in self.checklists if c.notes]) 
     # @NOTE:1: below will prevent error for those that do not have `notes` column 
     # @NOTE:2: in any case this may issue a lot of SQL statements to load all subclasses of checklists relationship, so is not really efficient 
     return len([c for c in self.checklists 
        if hasattr(c, 'notes') and c.notes]) 

    @number_of_comments.expression 
    def number_of_comments(cls): 
     from sqlalchemy import select 
     ce, cl, cla, clb = [ 
      _.__table__ for _ in (Cebola, Checklist, ChecklistA, ChecklistB)] 
     s = (
      select([func.count(cl.c.id).label("number_of_comments")]) 
      .select_from(cl.outerjoin(cla).outerjoin(clb)) 
      .where(or_(cla.c.notes != None, clb.c.notes != None)) 
      .where(cl.c.cebola_id == cls.id) 
      .correlate(cls) 
      .as_scalar() 
     ) 
     return s 

Использование в запросе:

q = session.query(Cebola, Cebola.number_of_comments) 
for cebola, number_of_comments in q.all(): 
    print(cebola, number_of_comments) 
+0

Спасибо за ваш ответ. Я просто сомневаюсь в использовании сеанса в гибридном выражении. Как я могу получить его, если нет экземпляра объекта? – amleczko

+0

Вы правы, использование 'session' в гибридном выражении - это не то, что нужно делать. У меня просто был простой запрос для выполнения этой работы с помощью 'with_polymorphic' (что делает все эти приятные« LEFT OUTER JOIN »для вас). Но вы можете построить одно и то же выражение, используя выражения напрямую. – van

+0

Обновлен ответ, используя только выражения без экземпляра Query, которые будут обрабатывать один и тот же запрос. В зависимости от базы данных и количества таблиц вы даже можете переместить предложения 'where' в часть условий' join', так как на некоторых базах данных это может быть быстрее. – van

Смежные вопросы