SQLAlchemy和遍历:如何为从数据库检索的对象添加遍历所需属性?

1 投票
1 回答
596 浏览
提问于 2025-04-17 17:24

我有一个资源树结构,像这样:

Root
|
|
\-- Article
|     |
|     \-- 1
|     \-- 2
|
\-- User
      |
      \-- 1
      \-- 2

当用户访问“/Article”时,我会显示所有文章的列表:

@view_config(context='resource.ArticleDispatcher', renderer='nothing-related')
def article_list(context, resource):
    articles = request.db.query(Article)
    return {'articles': articles}

但是在模板中,我发现我无法调用 'req.resource_url(ARTICLE_OBJECT)',因为我从数据库中获取的 'articles' 对象既没有名称也没有父级设置。

现在我不知道在这种情况下该如何生成网址... :-( 我的设计是不是有问题?

1 个回答

3

为了让你的文章对象能够自动正确地插入到遍历树中,最直接的方法是通过父对象的 __getitem__ 方法来访问它们。如果你只是访问单个文章,比如 /Articles/123,这样做是没问题的。

但是,当你要显示一个文章列表时,其实并不是在逐个访问文章。你只是碰巧想在 /Articles 显示一系列文章,所以这个情况并不直接适用于遍历(遍历是指 访问一个URI)。不过,有几种简单的方法可以让它看起来像是在进行遍历:

@view_config(context='resource.ArticleDispatcher')
def article_list(context, request):
    all_articles_ids = context.magically_get_ids_of_all_articles()
    articles = [context[id] for id in all_articles_ids]
    return {'articles': articles}

在这里,你需要知道所有文章的ID,然后通过遍历一个一个地获取它们的子项,这样就能把它们插入到遍历上下文中。不过在很多情况下(尤其是使用SQL数据库时),这样做效率并不高,因为你需要为每个对象单独发起一个查询。

第二个,更现实的例子是:手动将文章插入到遍历上下文中:

@view_config(context='resource.ArticleDispatcher')
def article_list(context, request):
    articles = context.adopt_children(request.db.query(Article))
    return {'articles': articles}

class ArticleDispatcher(object):
    def adopt_children(self, children):
        for child in children:
            child.__name__ = child.id # actually I'd made __name__ a property of the Article model
            child.__parent__ = self
        return children

第三个例子是:干脆不去假装你在遍历文章,而是直接做一些像这样的事情:

req.resource_url(ARTICLE_DISPATCHER) + '/' + article.id

在这种情况下,你甚至可能不需要查询完整的文章对象,只需要查询名称和ID(在某些情况下这样可能会更快):

@view_config(context='resource.ArticleDispatcher')
def article_list(context, resource):
    name_id_tuples = request.db.query(Article.id, Article.name).all()
    return {'articles': name_id_tuples}

撰写回答