【问题标题】:Query returning every cover in db for each entry?查询为每个条目返回数据库中的每个封面?
【发布时间】:2014-11-09 05:35:11
【问题描述】:

我的查询似乎为每个封面返回 1 个条目。也就是说,如果我在数据库中有 3 个封面,那么查询将使用每个不同的封面返回条目 #1 三次。因为我有 7 个条目,所以我得到了 21 个结果。如何构建查询以返回与条目关联的封面?

这是我所拥有的:

@app.route('/list', methods=['GET', 'POST'])
def list():
    entries = Book.query.order_by(Book.id.desc()).all()
    cvr_entries = Cover.query.filter(Cover.book).all()

    ### Other queries I've tried ###

    # cvr_entries = Cover.query.join(Cover.book).all()
    # cvr_entries = Cover.query.filter(Cover.book.any())
    # cvr_entries = Cover.query.filter(Cover.book.any()).all()

    return render_template(
        'list.html',
        entries=entries,
        cvr_entries=cvr_entries)

这是/list 输出页面:

{% for entry in entries %}
{% for cvr in cvr_entries %}

<article class="entry">
    <img src="/static/data/covers/{{ cvr.name }}" alt="Cover for {{ entry.title }}" />
    <ul class="entry-info">
        <li class=""><h2>{{ entry.title }}</h2></li>
        <li class="">Summary: {{ entry.summary|truncate( 30, true ) }}</li>
    </ul>
</article>

{% endfor %}
{% endfor %}

切换 entries 和 cvr_entries for 循环的顺序不会改变任何事情。我也尝试添加first() 而不是all(),但这会导致显示错误

TypeError: 'Cover' object is not iterable

所以这是一个半身像。我不明白如何构建查询。

这是我的模型,应@jonafato 的要求:

book_to_cover = db.Table('book_to_cover',
    db.Column('cover_id', db.Integer, db.ForeignKey('cover.id')),
    db.Column('book_id', db.Integer, db.ForeignKey('book.id'))
)

class Book(db.Model):
    __tablename__ = 'book'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String())
    summary = db.Column(db.Text)

    book_to_cover = db.relationship('Cover', secondary=book_to_cover,
        backref=db.backref('book', lazy='dynamic'))

    def __repr__(self):
        return "<Book (title='%s')>" % (self.title)


class Cover(db.Model):
    __tablename__ = 'cover'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String())

    def __repr__(self):
        return "<Cover (name='%s')>" % self.name

【问题讨论】:

  • 你能发布你的 SQLAlchemy 模型吗?特别是,您是否在Book 和Cover 之间定义了关系(带有反向引用)?如果是这样,您应该能够完全删除cvr_entries 查询并将您的内部for 循环更改为类似于{% for cvr in entry.covers %}。
  • 除了我之前的评论,您可以使用joinedload 来防止循环内不必要的查询。
  • @jonafato 我试过cvr_entries = Cover.query.options(joinedload(Cover.book)),但我得到了NameError: global name 'joinedload' is not defined。我也尝试了entry.covers 方法,但根本没有返回任何条目。
  • 必须先从sqlalchemy.orm导入joinedload才能使用。
  • 我导入它并得到错误InvalidRequestError: 'Cover.book' does not support object population - eager loading cannot be applied. 我找到了一个解决方案here,但这不起作用。我还将我的加载从 dynamic 更改为 joined 无济于事。

标签: database flask flask-sqlalchemy


【解决方案1】:

一般来说,你迭代模型——你的关系应该允许你这样做:

books = Book.query.all()
return render_template('list.html', books=books)

然后在您的 Jinja2 list.html 模板中:

{% for book in books %}
    <h3>{{ book }}</h3>
    <ul>
    {% for cover in book.book_to_cover %}
        <li>{{ cover }}</li>
    {% endfor %}
    </ul>
{% endfor %}

将book_to_cover 重命名为covers 会更自然,以使其在访问模型时更像自然语言。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多