【问题标题】:Python Sqlalchemy access many to many data in viewPython Sqlalchemy 访问视图中的多对多数据
【发布时间】:2018-09-16 07:01:11
【问题描述】:

我有一个多对多的关系。插入数据是没有问题的,但是我不知道如何正确获取jinja2/view中的数据。我有一个可行的方法,但感觉像是一种解决方法。

class Post(Base):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    title = Column(Text, nullable=False)
    description = Column(Text, nullable=True)
    children_PostBelongsCategory = relationship("PostBelongsCategory")
    # etc.

class Category(Base):
    __tablename__ = 'categories'
    category_name = Column(Text, primary_key=True)
    # etc.

PostCategory 的多对多关系:

class PostBelongsCategory(Base):
    __tablename__ = 'postbelongstocategories'
    post_id = Column(Integer, ForeignKey('posts.id'), primary_key=True)
    category_id = Column(Text, ForeignKey('categories.category_name'), primary_key=True)  
    child = relationship("Category")

我现在的做法是查询所有 Post 项目,查询所有 PostBelongsCategory 项目,然后使用 if 循环比较 id 的两个嵌套 for 循环:

{% for post in posts %}
<div class="row">
    <div class="col-xs-12">
        <div class="post-item">
            <h1> {{ post.title }} </h1>
            <p> {{ post.description }} </p>
            {% for cat in categories %}
                {% if cat.post_id == post.id %}
                    <p> {{ cat.category_id }} </p>
                {% endif %}
            {% endfor %}
        </div>
    </div>
</div>
{% endfor %}

我认为如果表非常大,我的方法可能会导致性能问题(但我不确定这里,也许有人可以在这里帮助我)。同样如前所述,我的方法感觉像是一种解决方法。有没有更好的方法从多对多获取数据?

到目前为止我尝试的是使用lazyload

Post.query.options(lazyload('children_PostBelongsCategory')).order_by(desc("created_on")).all()

这没有错误,但也没有什么新东西。我目前正在阅读有关加入/加载选项的信息,但我不确定我是否走在正确的道路上。

【问题讨论】:

  • @IljaEverilä 我是如此接近,只需要正确的语法。非常感谢,它有效。如果你回答我的问题,我会接受。也很高兴知道延迟加载是默认的。
  • 与正确的方法相比,我的方法是否会导致性能问题?
  • @IljaEverilä 谢谢!
  • 顺便说一句,您的真实关联对象除了外键之外还有其他列吗?如果没有,您可以稍微简化设置并将其用作辅助表,从而无需通过 2 个关系来访问类别。

标签: python flask sqlalchemy many-to-many jinja2


【解决方案1】:

使用定义好的ORM关系访问相关对象:

{% for post in posts %}
    ...
            {% for assoc in post.children_PostBelongsCategory %}
                <!-- do something with assoc.child here -->
            {% endfor %}
    ...
{% endfor %}

默认情况下,关系是延迟加载的,因此在您的情况下无需传递该选项。您的原始方法有点像手动嵌套循环连接,但在 Python 中执行,如果您有很多类别,性能可能会较差。

实际上,延迟加载意味着每个关系属性访问都会发出一个新的 SELECT 以获取相关对象。如果您有很多帖子,这可能会成为一个问题。一种解决方案是在获取帖子的同一查询中急切加载相关对象。一个很好的入门是joined eager loading

# Note the chaining in the passed options
Post.query.\
    options(joinedload('children_PostBelongsCategory')
            .joinedload('child')).\
    order_by(Post.created_on.desc()).\
    all()

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    • 2011-10-01
    • 2014-10-29
    • 1970-01-01
    • 2011-01-09
    • 2020-07-14
    相关资源
    最近更新 更多