第11章 博客文章

一. 提交和显示博客文章

app/models.py:博客文章的数据库模型:Post模型

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))

class User(UserMixin, db.Model):
    __tablename__ = "users"
    ...
    posts = db.relationship('Post', backref='author', lazy='dynamic')

博客文章包含正文,时间戳以及和User模型之间的一对多关系。

app/main/forms.py:应用首页的博客文章表单:

class PostForm(FlaskForm):
    body = TextAreaField("What's on your mind?", validators=[DataRequired()])
    submit = SubmitField('Submit')

index()视图函数处理博客文章表单并把以前发布的博客文章列表传给模板,文章列表按时间戳进行降序排列。

app/main/views.py:处理博客文章的首页路由

@main.route('/', methods=['POST', 'GET'])
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'))
    posts = Post.query.order_by(Post.timestamp.desc()).all()
    return render_template('index.html', form=form, posts=posts)

注意,新文章对象的author属性值为表达式current_user._get_current_object()。变量current_user由Flask-Login提供,与所有上下文变量一样,实现为线程内的代理对象。这个对象的表现类似用户对象,但实际上确是一个轻度包装,包含真正的用户对象。而数据库要真正的用户对象,因此要在代理对象上调用_get_current_object()方法。

app/templates/index.html:显示博客列表的首页模板

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}Flasky{% endblock %}

{% block page_content %}

{% if current_user.can(Permission.WRITE) %} {{ wtf.quick_form(form) }} {% endif %}
{% endblock %}

博客文章列表通过HTML无序列表实现,并自定义了一个CSS类。页面左侧会显示作者的小头像,头像和作者的用户名都渲染成链接,指向用户的资料页面。所用的CSS样式都存储在static目录下的style.css文件中:

.profile-thumbnail {
    position: absolute;
}
.profile-header {
    min-height: 260px;
    margin-left: 280px;
}
ul.posts {
    list-style-type: none;
    padding: 0px;
    margin: 16px 0px 0px 0px;
    border-top: 1px solid #e0e0e0;
}
ul.posts li.post {
    padding: 8px;
    border-bottom: 1px solid #e0e0e0;
}
ul.posts li.post:hover {
    background-color: #f0f0f0;
}
div.post-date {
    float: right;
}
div.post-author {
    font-weight: bold;
}
div.post-thumbnail {
    position: absolute;
}
div.post-content {
    margin-left: 48px;
    min-height: 48px;
}

运行结果(请先忽略每篇博客的编辑链接和详情链接):

第11章 博客文章_第1张图片

二. 在资料页中显示博客文章

app/main/views.py:获取博客文章的资料页面路由

@main.route('/user/')
def user(username):
    user = User.query.filter_by(username=username).first_or_404()
    posts = user.posts.order_by(Post.timestamp.desc()).all()
    return render_template('user.html', user=user, posts=posts)

用户发布的博客文章列表通过User.posts关系获取。User.posts返回结果类似于查询对象,因此可以像常规查询对象那样在其上调用过滤器order_by()。

与index.html模板一样,user.html模板也要使用一个HTML

    元素渲染博客文章列表。因此我们可以将生成文章列表的HTML片段移到一个单独的文件中,然后再index.html和user.html中使用Jinjia2提供的include指令将其导入。

    app/templates/_posts.html:渲染博客文章列表的模板

    注:_posts.html中下划线不是必须的,这是一种习惯写法,以区分完整模板和局部模板。

    app/templates/user.html:显示有博客文章的资料页面模板

    ...
    

    Posts by {{ user.username }}

    {% include '_posts.html' %} ...

    app/templates/index.html也是用{% include '_posts.html' %}进行相应调整。

    运行结果(编辑链接和详情链接也请先忽略,后续介绍讲解):

    第11章 博客文章_第2张图片

你可能感兴趣的:(Flask)