#python #flask #sqlalchemy #flask-sqlalchemy
#python #flask #sqlalchemy #flask-sqlalchemy
Вопрос:
У меня есть приложение, использующее SQLAlchemy.
У нас есть две модели (которые актуальны).
- Родительский
- Дочерний элемент
У каждого родителя может быть несколько дочерних элементов, на которые ссылается внешний ключ. У дочернего элемента должен быть родитель
Я хотел бы иметь атрибут экземпляра для каждого родителя, который равен имени младшего дочернего элемента.
На данный момент я работаю с функцией youngest_child()
, которая перебирает всех дочерних элементов родительского элемента, находит самого младшего и возвращает его имя. Очевидно, что это неэффективно делать это каждый раз.
Вместо этого всякий раз, когда создается новый дочерний элемент или у дочернего элемента обновляется его родительский элемент, я хотел бы установить youngest_child
атрибут для родительского элемента.
Есть ли способ сделать это с помощью SQLAlchemy?
Комментарии:
1. Если в таблице указаны возраст / день рождения детей, выберите parent_id в качестве первого параметра. Сортируйте по возрасту и выбирайте только первый.
2. @Wimanicesir это фактически то, что я делаю, хотя я определенно должен сначала отсортировать. Но мне интересно, есть ли способ, чтобы мне не приходилось каждый раз выполнять этот поиск и вместо этого сохранять имя младшего дочернего элемента в таблице
3. После того, как вы сохраните самого младшего дочернего элемента, в следующий раз вам нужно будет проверять только при вставке новых дочерних элементов, если они младше самого младшего дочернего элемента. Если вы имеете в виду более молодую, более новую запись. Просто всегда заменяйте его при вставке нового дочернего элемента.
Ответ №1:
Я бы решил это с помощью гибридного свойства:
from sqlalchemy.ext.hybrid import hybrid_property
class Parent(Base):
...
children = relationship("Child", order_by="Child.age")
@hybrid_property
def youngest_child(self):
"""
children are already sorted by their age in the relationship.
This offers an advantage in performance when children are frequently
accessed through their sorted property.
"""
return self.children[0] if self.children
# - - - - - - - - - - - - - - - - - -
# Another approach – without pre-defined ordering
class Parent(Base):
...
# Don't order the children
children_no_order = relationship("Child")
@hybrid_property
def youngest_child_no_order(self):
"""
children are not automatically sorted by their age.
Do so with a subquery hybrid.
"""
query = Child.query
.filter(Child.parent_id == self.id)
.order_by(Child.age)
.first()
# I chose to write this query in this format bc it helps with debugging
# You could just as easily return the query without saving its state...
return query
Для более продвинутой реализации см. раздел Гибридные отношения коррелированных подзапросов.