带分页的单个帖子路由 - Flask

2 投票
1 回答
1751 浏览
提问于 2025-04-18 03:59

目标:为每篇文章或博客帖子设置一个单独的链接,并加入分页功能(使用SQL-Alchemy),这样用户就能方便地浏览之前和之后的帖子。

目前,我有以下内容:

@app.route('/articles/ind/<int:id>', endpoint='article')
def indarticle(id = 1):
    posts= Post.query.paginate(id, 1, False)
    return render_template('article.html',
        title = "Article",
        posts = posts)

可以看到,我每页只显示一篇文章,所以假设文章的ID从1开始,文章的ID和页码是对应的。但是,如果它们不匹配(或者某篇文章从数据库中被删除了),那么链接和显示的页面就会不一致。我可以通过遍历表格中的行来找出哪个页码对应哪个正确的文章ID;不过,这样做似乎不太高效,也不太实际。

有什么好的方法来解决这个问题吗?

更新: 在下面的回答基础上,我创建了以下内容:

models.py

class Post(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(100))
body = db.Column(db.Text)
timestamp = db.Column(db.DateTime)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

def get_count(self):
    return db.session.query(Post).count()

def prev_post(self):
    count = self.get_count()
    pid = self.id
    while (count > 0):
        prev_post = None
        pid = pid - 1
        if db.session.query(Post).get(pid) is not None:
            prev_post = db.session.query(Post).get(pid)
            break
        else:
            count = count - 1

    return prev_post

def next_post(self):
    count = self.get_count()
    pid = self.id
    while (count > 0):
        next_post = None
        pid = pid + 1
        if db.session.query(Post).get(pid) is not None:
            next_post = db.session.query(Post).get(pid)
            break
        else:
            count = count - 1

    return next_post

def has_prev(self):
    return True if self.prev_post() is not None else False

def has_next(self):
    return True if self.next_post() is not None else False

这样,我就可以获取下一篇和上一篇文章,并且可以轻松检查它们是否存在,这就像flask-sqlalchemy处理分页一样。

1 个回答

2

为了确保我们讨论的是同一件事,分页有两种类型……

第一种是Flask支持的那种……就是把所有文章都调用出来,每页显示X篇文章……

第二种是你在某篇文章里,想要向前和向后翻页。

听起来你想做的是第二种。

我做的就是在我的POST模型里写了两个静态方法,用来找出上一篇和下一篇文章……然后通过我的视图函数把这些值传给模板。

POST模型的静态方法

模型

@staticmethod
def prev_post(pid):
    count = Post.get_count()
    while (count > 0):
        prev_post = None
        pid = pid - 1
        if db.session.query(Post).get(pid) is not None:
            prev_post = db.session.query(Post).get(pid)
            break
        else:
            count = count - 1
    return prev_post

@staticmethod
def next_post(pid):
    count = Post.get_count()
    while (count > 0):
        next_post = None
        pid = pid + 1
        if db.session.query(Post).get(pid) is not None:
            next_post = db.session.query(Post).get(pid)
            break
        else:
            count = count - 1
    return next_post

prev_post函数是怎么工作的。

  1. 用文章的数量来设置我的循环范围。
  2. 在prev_post的情况下,给一个None值,这样如果找不到上一篇文章,模板的逻辑也能正常工作。如果没有给None值,传到视图时会出错。
  3. 在prev_post的情况下,每次循环时把pid减1,然后检查数据库里是否有这个条目。
  4. 在循环中,每次都减1。
  5. 第一次找到匹配的,就跳出循环,把prev_post的None值替换成找到的post.id。

当然,next函数的逻辑完全一样,只不过是把pid加1,而不是减1。

这样就解决了删除文章后显示错误数量的问题。而且,你会注意到我不需要返回所有文章并逐个循环。我只需获取数量,然后逐个检查pid是否存在。因为循环总是从当前文章开始,所以我很少需要循环超过2到3次就能找到结果。简而言之,这个过程使用的内存相对较少。

现在我可以在我的视图中调用这些函数……

视图

@app.route('/<path:url>', methods=['GET', 'POST']) def
display_post(url):
    post = Post.get_post(url)
    next_post = Post.next_post(post.id)
    prev_post = Post.prev_post(post.id)
    return render_template('post.html',
                           next=next_post, prev=prev_post, post=post)

这是模板。

模板

{% extends "base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<H2>{{ post.title }}</H2>
<b>Posted {{ post.pub_date|dts }} in <a href="{{ url_for('display_topic', url=post.topic.url) }}">{{post.topic}}</a></b>
{{post.body|markdown}}
{% if prev.url is defined %}
<a href="{{ url_for('display_post', url=prev.url) }}"><<< {{prev.title}}</a>
{% endif %}
{% if prev.url is not defined and next.url is not defined %}{% else %} | {% endif %}
{% if next.url is defined %}
<a href="{{ url_for('display_post', url=next.url) }}">{{next.title}} >>></a>
{% endif %}
{% if current_user.is_authenticated() %}
<p><a href="{{ url_for('edit_post', url=post.url) }}">edit</a></p>
<p><a href="{{ url_for('delete_post', url=post.url) }}">delete</a></p>
{% endif %}
{% endblock %}

模板只会在存在下一篇或上一篇文章时显示链接。

撰写回答