Подтвердить что ты не робот

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

... но сейчас я просто пытаюсь заставить это работать. Огромное спасибо тому, кто может помочь мне в этом, поскольку я пытался понять это уже давно.

4b9b3361

Ответ 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)