第十一章 博客文章(二)

如果在首页和资料页面显示全部文章,页面加载速度会变慢,而且有点不切实际。在WEB浏览中,内容过多的网页需要花费更多的时间生成、下载和渲染。解决办法是:分页显示数据并分段渲染。

一. 创建虚拟博客文章数据

实现博客文章分页,需要大量的数据,手动添加费时费力。Python有多个包可以提供自动化解决方案,用于生成虚拟信息,其中比较完善的是Faker,这个包用pip安装:

pip install faker

Faker包并不是这个应用的依赖,因为它只在开发过程中使用。为了区分生产环境的依赖和开发环境的依赖,我们使用requirements目录取代requirements.txt文件,在该目录下分别创建dev.txt和pro.txt文件;由于2个环境使用的大部分依赖都是相同的,可以再创建一个common.txt,在dev.txt和pro.txt中使用-r参数将其导入即可:

requirements/dev.txt:开发需求文件

-r common.txt
faker==0.7.18

接下来,我们创建一个新模块fake.py,分别生成虚拟用户和博客文章:

from random import randint
from sqlalchemy.exc import IntegrityError
from faker import Faker
from . import db
from .models import User, Post


def users(count=100):
    fake = Faker()
    i = 0
    while i < count:
        u = User(email=fake.email(),
                 username=fake.user_name(),
                 password='password',
                 confirmed=True,
                 name=fake.name(),
                 location=fake.city(),
                 about_me=fake.text(),
                 member_since=fake.past_date())
        db.session.add(u)
        try:
            db.session.commit()
            i += 1
        except IntegrityError:
            db.session.rollback()


def posts(count=100):
    fake = Faker()
    user_count = User.query.count()
    for i in range(count):
        u = User.query.offset(randint(0, user_count - 1)).first()
        p = Post(body=fake.text(),
                 timestamp=fake.past_date(),
                 author=u)
        db.session.add(p)
    db.session.commit()

Faker包提供的随机信息生成器,可以生成看起来很逼真的姓名,电子邮件地址,句子等等。注意:由于用户的电子邮件地址和用户名必须是唯一的,Faker随机生成这些信息时会有重复的风险,此时提交数据库会话时会抛出IntegrityError异常,此时需要捕获异常,回滚数据库提交会话

随机生成文章时,要为每篇文章随机指定一个用户,为此,我们使用offset查询过滤器,这个过滤器会跳过参数指定的记录数量。为了每次都得到不同的用户,我们使用randint(0, user_count - 1)设定一个随机的偏移,然后调用first方法。

运行:

二. 在页面中渲染数据

为了支持分页,而对首页路由和资料页路由的相关查询对象使用paginate()方法。

app/main/view.py:分页显示博客文章列表

@main.route('/', methods=['GET', 'POST'])
def index():
    form = PostForm()
    if current_user.can(Permission.WRITE) and form.validate_on_submit():
        post = Post(body=form.body.data,
                    author=current_user._get_current_object())
        db.session.add(post)
        db.session.commit()
        return redirect(url_for('.index'))
    page = request.args.get('page', 1, type=int)
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(
        page, per_page=current_app.config['FLASKY_POSTS_PER_PAGE'],
        error_out=False)
    posts = pagination.items
    return render_template('index.html', form=form, posts=posts,
                           pagination=pagination)

渲染的字符串从请求的查询字符串request.args中获取,如果没有明确指定,则默认渲染第一页,参数type=int确保参数在无法转换成整数时返回默认值。

为了显示某页中的记录,Post.query.order_by(Post.timestamp.desc())查询对象不能调用all()方法了,要把all()换成Flask-SQLAlchemy提供的paginate()方法。页数是paginate()方法的首个参数,也是唯一必须参数;可选参数per_page用来指定每页显示的记录数,默认为20;另一个可选参数为error_out,为True(默认)时,如果请求的页数超出了范围,则返回404错误,如果设为False,页面超出范围时显示一个空列表。

app/main/views.py:用户详情页博客文章列表进行分页显示

@main.route('/user/<username>')
def user(username):
    user = User.query.filter_by(username=username).first_or_404()
    page = request.args.get('page', 1, type=int)
    pagination = user.posts.order_by(Post.timestamp.desc()).paginate(
        page, per_page=current_app.config['FLASKY_POSTS_PER_PAGE'],
        error_out=False)
    posts = pagination.items
    return render_template('user.html', user=user, posts=posts,
                           pagination=pagination)

最后记得在config.py中添加新增的配置项:

class Config:
    ...
    FLASKY_POSTS_PER_PAGE = int(os.environ.get('FLASKY_POSTS_PER_PAGE') or '20')

这样修改后,如果想查看第二页的文章,只需在URL后面加上查询字符串?page=2即可:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值