фильтровать вложенные дочерние элементы sqlalchemy на произвольную глубину - PullRequest
1 голос
/ 03 апреля 2019

У меня сложная модель. Допустим, он содержит 100 сущностей, каждый из которых так или иначе связан друг с другом. Некоторых много ко многим, некоторые один к одному, некоторые много к одному и так далее.

Все эти объекты имеют отметки времени start и end, указывающие допустимые диапазоны времени. При загрузке этих объектов с помощью запроса я хочу заполнить поля отношений только теми объектами, которые имеют отметки start и end, заключающие данную временную метку: например, datetime.now(), или вчера, или всякий раз.

Я определю здесь две модели, например, но предположим, что существует огромное количество других:

class User(base):
    __tablename__ = 'User'

class Role(base):
    __tablename__ = 'Role'

    user_id = Column(Integer, ForeignKey('User.uid'))
    user = relationship(User, backref=backref('Role')
    start = Column(DateTime, default=func.current_timestamp())
    end = Column(DateTime))

Теперь я хочу вернуть сущности через конечные точки отдыха в колбе. Итак, get может выглядеть примерно так в колбе:

def get(self, uid=None) -> Tuple[Dict, int]:
    query = User.query
    if uid:
        query.filter_by(uid=uid)
    return create_response(
        query.all()
        200
    )

Теперь я хочу ограничить Role сущности, возвращаемые в качестве дочерних элементов, User, возвращаемыми вышеупомянутым запросом. Очевидно, что это можно легко сделать, просто расширив query для фильтрации ролей. Проблема возникает, когда это масштабируется. Рассмотрим 100 вложенных уровней дочерних отношений. Теперь рассмотрим конечные точки отдыха, обеспечивающие get для любой из них. Было бы практически невозможно выписать query для правильной фильтрации каждого уровня ребенка.

Мое желаемое решение состояло в том, чтобы определить поведение загрузки для каждой сущности, делая все компонуемым. Например:

class User(base):
    __tablename__ = 'User'

    role = relationship("Role",
                     primaryjoin="and_(Role.start<={desired_timestamp} "
                                 "Role.end>={desired_timestamp})")

Проблема, конечно, в том, что мы не знаем наш desired_timestamp во время определения класса, поскольку он передается во время выполнения. Я думал о некоторых хаках для этого, таких как переопределение всего во время каждой среды выполнения, но я не доволен ими. У кого-нибудь есть понимание относительно "правильного" способа сделать что-то подобное?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...