SQLAlchemy - Написание гибридного метода для подсчета количества детей
Я использую Flask-SQLAlchemy, и я пытаюсь написать гибридный метод в родительской модели, которая возвращает количество дочерних элементов, которые она имеет, поэтому я может использовать его для фильтрации, сортировки и т.д. Здесь некоторый урезанный код того, что я пытаюсь:
# 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
Здесь я столкнулся с двумя проблемами. Во-первых, я не знаю, что именно вернуть в "child_count (cls)", который должен быть выражением SQL... Я думаю, что это должно быть что-то вроде
return select([func.count('*'), from_obj=Child).where(Child.parent_id==cls.parent_id).label('Child count')
но я не уверен. Другая проблема заключается в том, что я не могу импортировать класс Child из parent.py, поэтому я не мог использовать этот код. Есть ли способ использовать строку для этого? Например,
select([func.count('*'), from_obj='children').where('children.parent_id==parents.parent_id').label('Child count')
В конце концов, я хочу изменить метод на что-то вроде:
def child_count(cls, start_time, end_time):
# return the number of children whose "date" parameter is between start_time and end_time
... но сейчас я просто пытаюсь заставить это работать. Огромное спасибо тому, кто может помочь мне в этом, поскольку я пытался понять это уже давно.
Ответы
Ответ 1
В приведенном ниже коде показано все.
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)
Ответ 2
Я думаю, вы можете просто использовать простые ol 'len и hybrid_property, чтобы получить счет:
@hybrid_property
def child_count(self):
return len(self.children)
Из документа, похоже, он сделал бы трюк, если я что-то не упустил?
duggars = db.session.query(Parent).filter(Parent.child_count > 17)