колба: Получить все элементы от родителя в таблице с самостоятельной ссылкой: sqlalchemy.exc.ArgumentError: Ожидаемая сопоставленная сущность или выбираемая/таблица в качестве цели объединения

#flask-sqlalchemy #children #backreference #self-referencing-table

Вопрос:

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

 # Post model
class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    date_posted = db.Column(db.DateTime(100), nullable=False, default=datetime.utcnow)
    content = db.Column(db.Text, nullable=False)
    topic = db.Column(db.String(100), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    # thread structure using self-referencing see
    # https://docs.sqlalchemy.org/en/14/orm/self_referential.html
    parent_post = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True)
    child_posts = db.relationship('Post', backref='parent', lazy="joined", remote_side='Post.id') # background query

# display selected post thread route
@posts.route("/post_thread/<int:post_id>")
def post_thread(post_id):
    posts = Post.query.filter(Post.id==post_id).join(Post.id==Post.parent_post).all()
    # This works but to get only the selected post: posts = Post.query.where(Post.id==post_id)
    return render_template('post_thread.html', posts=posts, topic="Thread")
 

Ответ №1:

Я написал рекурсивную функцию, которая работает, но при этом не используется связь обратных ссылок, поэтому, я думаю, это не самый эффективный способ сделать это.

 # Recursive function to iterate down tree and return union of parent and children found
def union_children(post_id, posts):
    print("Looking for child posts")
    child_posts = Post.query.where(Post.parent_post==post_id)
    if child_posts:
        print("Child found")
        posts = posts.union(child_posts)
        for post in child_posts:
            posts = union_children(post.id, posts)
    return posts

@posts.route("/post_thread/<int:post_id>")
def post_thread(post_id):
    posts = Post.query.where(Post.id==post_id)
    posts = union_children(post_id, posts)
    return render_template('post_thread.html', posts=posts, topic="Thread")