2012-11-30 6 views
13

Sto utilizzando Flask-SQLAlchemy e sto provando a scrivere un hybrid method in un modello padre che restituisce il numero di figli che ha, quindi posso usarlo per filtrare, ordinamento, ecc. Ecco un codice ridotto di quello che sto cercando:SQLAlchemy - Scrittura di un metodo ibrido per il conteggio figlio

# parent.py 
from program.extensions import db 
from sqlalchemy.ext.hybrid import hybrid_method 

class Parent(db.Model): 
    __tablename__ = 'parents' 
    parent_id = db.Column(db.Integer, primary_key=True) 

    name = db.Column(db.String(80)) 
    children = db.relationship('Child', backref='parent', lazy='dynamic') 

    def __init__(self, name): 
     self.name = name 

    @hybrid_method 
    def child_count(self): 
     return self.children.count() 

    @child_count.expression 
    def child_count(cls): 
     return ????? 

# child.py 
from program.extensions import db 
from program.models import Parent 

class Child(db.Model): 
    __tablename__ = 'children' 
    child_id = db.Column(db.Integer, primary_key=True) 
    parent_id = db.Column(db.Integer, db.ForeignKey(Parent.parent_id)) 

    name = db.Column(db.String(80)) 
    time = db.Column(db.DateTime) 

    def __init__(self, name, time): 
     self.name = name 
     self.time = time 

Sto incontrando due problemi qui. Per uno, non so cosa esattamente per tornare nella "child_count (CLS)", che deve essere espressione di SQL ... penso che dovrebbe essere qualcosa come

return select([func.count('*'), from_obj=Child).where(Child.parent_id==cls.parent_id).label('Child count') 

ma io non sono sicuro. Un altro problema che ho è che non posso importare la classe Child da parent.py, quindi non potrei comunque usare quel codice. C'è un modo per usare una stringa per questo? Ad esempio,

select([func.count('*'), from_obj='children').where('children.parent_id==parents.parent_id').label('Child count') 

Alla fine, io voglio cambiare il metodo per qualcosa come:

def child_count(cls, start_time, end_time): 
    # return the number of children whose "date" parameter is between start_time and end_time 

... ma per ora, sto solo cercando di arrivare a questo lavoro. Enorme grazie a chiunque possa aiutarmi con questo, come ho cercato di capire da molto tempo ormai.

risposta

16

Il codice seguente mostra tutto.

class Parent(Base): 
    __tablename__ = 'parents' 
    # ... 

    @hybrid_property 
    def child_count(self): 
     #return len(self.children) # @note: use when non-dynamic relationship 
     return self.children.count()# @note: use when dynamic relationship 

    @child_count.expression 
    def child_count(cls): 
     return (select([func.count(Child.child_id)]). 
       where(Child.parent_id == cls.parent_id). 
       label("child_count") 
       ) 

    @hybrid_method 
    def child_count_ex(self, stime, etime): 
     return len([_child for _child in self.children 
      if stime <= _child.time <= etime ]) 

    @child_count_ex.expression 
    def child_count_ex(cls, stime, etime): 
     return (select([func.count(Child.child_id)]). 
       where(Child.parent_id == cls.parent_id). 
       where(Child.time >= stime). 
       where(Child.time <= etime). 
       label("child_count") 
       ) 


# usage of expressions: 
stime, etime = datetime.datetime(2012, 1, 1), datetime.datetime(2012, 1, 31) 
qry = session.query(Parent) 
#qry = qry.filter(Parent.child_count > 2) 
qry = qry.filter(Parent.child_count_ex(stime, etime) > 0) 
+0

Ah, grazie mille! Mi hai aiutato finalmente a capirlo. – fimbul

+0

Questo è esattamente quello che stavo cercando! Grazie! – Stanislav

-3

penso che si può semplicemente utilizzare ol' len pianura e hybrid_property per ottenere il conteggio:

@hybrid_property 
def child_count(self): 
    return len(self.children) 

Dalla doc, che sembra avrebbe fatto il trucco, a meno che non mi manca qualcosa?

duggars = db.session.query(Parent).filter(Parent.child_count > 17) 
+0

Non è un hybrid_property valido poiché 'len' non è un'operazione SQLAlchemy valida sulla relazione. – davidism

Problemi correlati