Flask学习之十二——用户评论

1. 评论在数据库中的表示

app/models.py: Comment 模型

class Comment(db.Model):
    __tablename__ = ‘comments‘
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    body_html = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    disabled = db.Column(db.Boolean)
    author_id = db.Column(db.Integer, db.ForeignKey(‘users.id‘))
    post_id = db.Column(db.Integer, db.ForeignKey(‘posts.id‘))

    @staticmethod
    def on_changed_body(target, value, oldvalue, initiator):
        allowed_tags = [‘a‘, ‘abbr‘, ‘acronym‘, ‘b‘, ‘code‘, ‘em‘, ‘i‘, ‘strong‘]
        target.body_html = bleach.linkify(bleach.clean(
            markdown(value, output_format=‘html‘),
            tags=allowed_tags, strip=True))

db.event.listen(Comment.body, ‘set‘, Comment.on_changed_body)

app/models/user.py: users表和posts表与comments表之间的一对多关系

class User(db.Model):
    # ...
    comments = db.relationship(‘Comment‘, backref=‘author‘, lazy=‘dynamic‘)

class Post(db.Model):
    # ...
    comments = db.relationship(‘Comment‘, backref=‘post‘, lazy=‘dynamic‘)

2. 提交和娴熟评论

app/main/forms.py: 评论输入表单

class CommentForm(Form):
    body = StringField(‘‘, validators=[Required()])
    submit = SubmitField(‘Submit‘)

app/main/views.py: 支持评论的文章路由

@main.route(‘/post/<int:id>‘, methods=[‘GET‘, ‘POST‘])
def post(id):
    post = Post.query.get_or_404(id)
    form = CommentForm
    if form.validate_on_submit():
        comment = Comment(body=form.body.data,
                          post=post,
                          author=current_user._get_current_object())
        db.session.add(comment)
        flash(‘Your comment has been published.‘)
        return redirect(url_for(‘.post‘, id=post.id, page=-1))
    page = request.args.get(‘page‘, 1, type=int)
    if page == -1:
        page = (post.comments.count()-1) / current_app.config[‘FLASKY_COMMENTS_PER_PAGE‘] + 1
        pagination = post.comments.order_by(Comment.timestamp.asc()).paginate(
            page, per_page=current_app.config[‘FLASKY_COMMENTS_PER_PAGE‘],
            error_out=False)
        comments = pagination.items
        return render_template(‘post.html‘, posts=[post], form=form,
                                comments=comments, pagination=pagination)

评论按照时间戳顺序排列,新评论显示在列表的底部。提交评论后,请求结果是一个重定向,转回之前的 URL,但是在 url_for() 函数的参数中把 page 设为 -1,这是个特殊的页数,用来请求评论的最后一页,所以刚提交的评论才会出现在页面中。程序从查询字符串中获取页数,发现值为 -1 时,会计算评论的总量和总页数,得出真正要显示的页数。

app/templates/_posts.html:添加链接到博客文章的评论

<a href="{{ url_for(‘.post‘, id=post.id) }}#comments">
    <span class="label label-primary">
        {{ post.comments.count() }} Comments
    </span>
</a>

#comments 后缀。这个后缀称为 URL 片段,用于指定加载页面后滚动条所在的初始位置。Web 浏览器会寻找 id 等于 URL 片段的元素并滚动页面,让这个元素显示在窗口顶部。这个初始位置被设为 post.html 模板中评论区的标题,即 <h4 id="comments">Comments<h4>。

3. 管理评论

app/templates/base.html:在导航条中加入管理评论链接

...
{% if current_user.can(Permission.MODERATE_COMMENTS) %}
<li><a href="{{ url_for(‘main.moderate‘) }}">Moderate Comments</a></li>
{% endif %}
...

app/main/views.py:管理评论的路由

@main.route(‘/moderate‘)
@login_required
@permission_required(Permission.MODERATE_COMMENTS)
def moderate():
    page = request.args.get(‘page‘, 1, type=int)
    pagination = Comment.query.order_by(Comment.timestamp.desc()).paginate(
        page, per_page=current_app.config[‘FLASKY_COMMENTS_PER_PAGE‘],
        error_out=False)
    comments = pagination.items
    return render_template(‘moderate.html‘, comments=comments,
                            pagination=pagination, page=page)

app/templates/moderate.html:评论管理页面的模板

{% extends "base.html" %}
{% import "_macros.html" as macros %}

{% block title %}Flasky - Comment Moderation{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Comment Moderation</h1>
</div>
{% set moderate = True %}
{% include ‘_comments.html‘ %}
{% if pagination %}
<div class="pagination">
    {{ macros.pagination_widget(pagination, ‘.moderate‘) }}
</div>
{% endif %}
{% endblock %}

这个模板将渲染评论的工作交给 _comments.html 模板完成,但把控制权交给从属模板之前,会使用 Jinja2 提供的 set 指令定义一个模板变量 moderate,并将其值设为 True。这个变量用在 _comments.html 模板中,决定是否渲染评论管理功能。

app/templates/_comments.html:渲染评论的正文

...
<div class="comment-body">
    {% if comment.disabled %}
    <p></p><i>This comment has been disabled by a moderator.</i></p>
    {% endif %}
    {% if moderate or not comment.disabled %}
        {% if comment.body_html %}
            {{ comment.body_html | safe }}
        {% else %}
            {{ comment.body }}
        {% endif %}
    {% endif %}
</div>
{% if moderate %}
    <br>
    {% if comment.disabled %}
        <a class="btn btn-default btn-xs" href="{{ url_for(‘.moderate_enable‘,    id=comment.id, page=page) }}">Enable</a>
    {% else %}
        <a class="btn btn-danger btn-xs" href="{{ url_for(‘.moderate_disable‘,id=comment.id, page=page) }}">Disable</a>
    {% endif %}
{% endif %}
...

_comments.html 模板中的按钮指定了 page 参数,重定向后会返回之前的页面。

app/main/vies.py: 评论管理路由

@main.route(‘/moderate/enable/<int:id>‘)
@login_required
@permission_required(Permission.MODERATE_COMMENTS)
def moderate_enable(id):
    comment = Comment.query.get_or_404(id)
    comment.disabled = False
    db.session.add(comment)
    return redirect(url_for(‘.moderate‘, page=request.args.get(‘page‘, 1, type=int)))

@main.route(‘/moderate/disable/<int:id>‘)
@login_required
@permission_required(Permission.MODERATE_COMMENTS)
def moderate_disable(id):
    comment = Comment.query.get_or_404(id)
    comment.disabled = True
    db.session.add(comment)
    return redirect(url_for(‘.moderate‘, page=request.args.get(‘page‘, 1, type=int)))

2015-05-27

时间: 2024-10-12 21:57:54

Flask学习之十二——用户评论的相关文章

Flask学习之十二 使用boostrap

英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xii-facelift 中文翻译地址:http://www.pythondoc.com/flask-mega-tutorial/facelift.html 开源中国社区:http://www.oschina.net/translate/the-flask-mega-tutorial-part-xii-facelift 其实这部分没什么好看的. boos

前端学习(十二):CSS排版

进击のpython 前端学习--CSS排版 本节主要介绍网页排版中主要格式化元素属性 帮助开发者把css技术与网页排版紧密联系到一起,来更好的实现网页设计效果 字体属性 字体 在日常工作中,我们会用到word来编写内容,比如可以对我们需要设置的内容设置字体.字号.颜色等设置 那么我们在网页中使用css样式时,同样也能做相关的设置 那我们可以试着为网页中的文字设置字体为微软雅黑 body{font-family:'微软雅黑'} 这里要注意不要设置不常用的字体,比如你给我来个'菲律宾体' 因为如果用

Docker学习(十二)中遇到的一些问题汇总

Docker学习(十二)中遇到的一些问题汇总 标签(空格分隔): docker docker: Error response from daemon: Conflict. The container name "/myubuntu" is already in use docker container ls docker container rm 容器名 docker rm $(docker ps -a -q) 删除所有容器 centos无法上网 ifup ens33 // 启用网卡

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

#HTTP协议学习# (十二)理解转发与重定向

本文转自:http://blog.csdn.net/meiyalei/article/details/2129120  生动清晰 解释一 转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求---->web服务器接受此请求-->调用内部的一个方法在容器内部完成请求处理和转发动作---->将目标资源发送给客户:在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的r

hbase 学习(十二)集群间备份原理

集群建备份,它是master/slaves结构式的备份,由master推送,这样更容易跟踪现在备份到哪里了,况且region server是都有自己的WAL 和HLog日志,它就像mysql的主从备份结构一样,只有一个日志来跟踪.一个master集群可以向多个slave集群推送,收到推送的集群会覆盖它本地的edits日志. 这个备份操作是异步的,这意味着,有时候他们的连接可能是断开的,master的变化不会马上反应到slave当中.备份个格式在设计上是和mysql的statement-based

虚拟机VMWare学习笔记十二 - 将物理机抓取成虚拟机

1. 安装VMware vCenter Converter Standalone Client 运行虚拟机,File -- Virtualize a Physical Machine 这时如果电脑中没有VMware vCenter Converter Standalone Client ,则会进行安装. 安装过程 之后图标会出现在桌面上,双击运行 选择连接到本地服务器,登陆 点击转换计算机 这个,可以将本地计算机抓取成虚拟机,也可以将其他可以访问的计算机(需知道管理员用户名及密码)抓取成虚拟机.

javascript基础学习(十二)

javascript之BOM 学习要点: 屏幕对象 History对象 Location对象 一.屏幕对象 Screen对象是一个由javascript自动创建的对象,该对象的主要作用是描述客户端的显示器的信息. 目前显示器分辨率为800X600或1024X768两种. screen.height:屏幕的高度 screen.width:屏幕的宽度 screen.availHeigh:屏幕的有效高度 screen.availWidth:屏幕的有效宽度 二.History对象 History对象可以

JavaScript学习总结(十二)——JavaScript编写类

在工作中经常用到JavaScript,今天总结一下JavaScript编写类的几种写法以及这几种写法的优缺点,关于JavaScript编写类的方式,在网上看到很多,而且每个人的写法都不太一样,经常看到的就是以下几种方式. 1.构造函数方式 用构造函数模拟"类",在其内部用this关键字指代实例对象. 基本语法: function 类名(){     this.属性名;//公共属性     var 属性名;//私有属性    /*凡是定义类的公共属性和公共方法都要使用this*/