flask-SQLAlchemy выполняет функцию перед вставкой / обновлением

#python #flask #sqlalchemy #flask-sqlalchemy

#python #flask #sqlalchemy #flask-sqlalchemy

Вопрос:

У меня есть приложение, использующее SQLAlchemy.

У нас есть две модели (которые актуальны).

  1. Родительский
  2. Дочерний элемент

У каждого родителя может быть несколько дочерних элементов, на которые ссылается внешний ключ. У дочернего элемента должен быть родитель

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

На данный момент я работаю с функцией 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
 

Для более продвинутой реализации см. раздел Гибридные отношения коррелированных подзапросов.