带分页的单个帖子路由 - Flask
目标:为每篇文章或博客帖子设置一个单独的链接,并加入分页功能(使用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函数是怎么工作的。
- 用文章的数量来设置我的循环范围。
- 在prev_post的情况下,给一个None值,这样如果找不到上一篇文章,模板的逻辑也能正常工作。如果没有给None值,传到视图时会出错。
- 在prev_post的情况下,每次循环时把pid减1,然后检查数据库里是否有这个条目。
- 在循环中,每次都减1。
- 第一次找到匹配的,就跳出循环,把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 %}
模板只会在存在下一篇或上一篇文章时显示链接。