У меня есть запрос, который возвращает объект User
. У User
есть несколько Post
, которые они сделали. Когда я выполняю запрос, я хочу отфильтровать сообщения, найденные в User.post
, на основе определенного времени. Например, чтобы вернуть только сообщения в течение 1 дня с заданной временной метки.
class User(base):
__tablename__ = 'User'
class Post(base):
__tablename__ = 'Post'
user_id = Column(Integer, ForeignKey('User.uid'))
user = relationship(User, backref=backref('post')
time = Column(DateTime, default=func.current_timestamp())
Есть ли способ динамически изменить способ загрузки дочерних элементов с помощью orm и указать это во время запроса? Что-то вроде (псевдокод):
User.query.filter_child(Post.time in timespan)
Важно отметить, что я не хочу отфильтровывать родителей, если нет детей, соответствующих критериям. Я хочу фильтровать только детей, загруженных формой для заданных пользователей.
Связано, но ваша ссылка включает фильтрацию родителя на основе дочерних атрибутов. В случае моего вопроса я не хочу фильтровать родителя на основе дочерних атрибутов, а только ограничивать дочерние элементы, загруженные внутри родителя, заданным атрибутом.
На самом деле я попробовал outerjoin
с filter
, но в результате я не получил никаких объектов пользователя, когда не было сообщений, соответствующих фильтру.
Я не уверен, что это то, что вы ищете, но что не так с этим подходом KISS?
Post.query.filter(Post.user == <username>).filter(
Post.time > START_OF_DAY).filter(Post.time < END_OF_DAY).all()
Это возвращает набор объектов Post
. Я хочу получить User
объекты, но я хочу, чтобы их встроенные Post
коллекции (User.post) имели набор объектов, отфильтрованных по некоторым критериям (временным меткам).
Ага, теперь понял. Какова практическая ситуация, для которой вы хотите это? Я могу представить, что могут быть другие способы достижения вашей цели (хотя с технической точки зрения это интересный вопрос)
Создание вычислительно эффективных способов извлечения информации. Извлечение данных, а затем изменение их структуры данных часто может быть менее эффективным, чем непосредственное извлечение структуры данных, которая вам нужна в первую очередь.
Загрузка пользовательских отфильтрованных коллекций выполняется с использованием contains_eager()
. Поскольку цель состоит в том, чтобы загрузить все объекты User
, даже если у них нет объектов Post
, соответствующих критериям фильтрации, следует использовать outerjoin()
, а предикаты для сообщений помещать в предложение ON
соединения:
end = datetime(2019, 4, 10, 12, 0)
start = end - timedelta(days=1)
# If you want to use half closed intervals, replace `between` with
# suitable relational comparisons.
User.query.\
outerjoin(Post, and_(Post.user_id == User.uid,
Post.time.between(start, end))).\
options(contains_eager(User.post))
Связанный, если не дубликат stackoverflow.com/questions/21924347/…. Единственная разница будет заключаться в использовании
outerjoin
вместоjoin
.