评论在数据库中的表示

由于评论和2个模型有关系,分别是谁发了评论,以及评论了哪个文章,所以这次要更新数据库模型

models.py 创建用户评论数据库模型

class Comment(db.Model):
__tablename__ = 'comments'
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text)
timestamp = db.Column(db.DateTime,index=True,default=datetime.utcnow)
body_html = db.Column(db.Text)
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)

User和Post里面也要和Comment设置相应的关系

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

提交和显示评论

main/forms.py 创建评论输入表单

class CommentForm(FlaskForm):
body = StringField('输入你的评论',validators=[DataRequired()])
submit = SubmitField('提交')

为支持评论更新路由post

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():
# current_user(上下文代理对象)._get_current_object() 真正的User对象
comment = Comment(body=form.body.data,
post=post,
author=current_user._get_current_object())
db.session.add(comment)
flash('你已经发布了新评论.')
# page设为-1,用来请求评论的最后一页,刚提交的评论才会出现在页面中
return redirect(url_for('.post', id=post.id, page=-1))
page = request.args.get('page', 1, type=int)
# 程序获取页数,发现时-1时,会计算总量和总页数得出真正显示的页数
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)

评论模板 _comment.html

<ul class="comments">
{% for comment in comments %}
<li class="comment">
<div class="comment-thumbnail">
<a href="{{ url_for('.user', username=comment.author.username) }}">
<img class="img-rounded profile-thumbnail" src="{{ comment.author.gravatar(size=40) }}">
</a>
</div>
<div class="comment-content">
<div class="comment-date">{{ moment(comment.timestamp).fromNow() }}</div>
<div class="comment-author"><a href="{{ url_for('.user', username=comment.author.username) }}">{{ comment.author.username }}</a></div>
<div class="comment-body">
{% if comment.body_html %}
{{ comment.body_html | safe }}
{% else %}
{{ comment.body }}
{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>

评论引入post.html

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% import '_macros.html' as macros %}
{% block title %}Flasky - 文章{% endblock %} {% block page_content %}
{% include '_posts.html' %} <h4 id="comments">评论</h4>
{% if current_user.can(Permission.COMMENT) %}
<div class="comment-form">
{{ wtf.quick_form(form) }}
</div>
{% endif %}
{% include '_comments.html' %}
{% if pagination %}
<div class="pagination">
{{ macros.pagination_widget(pagination, '.post', fragment='#comments', id=posts[0].id) }}
</div>
{% endif %}
{% endblock %}

上面加在 _posts.html里面的这段话,在url地址后面,加了一个 #comments

这个叫做URL片段

可以理解为:#这个符号,在URL地址里面相当于分隔符

#左边的,代表真实URL,对外的,就是普通用户可以看到的URL

#右边的,代表对网页内部的代码,在浏览器的地址栏是看不到的,他针对的是,当前页面HTML文件内,id=comments的内容

具体作用是:当加载这个页面时,直接会将这个id处于的位置,滚到页面顶端

类似于平时的用户体验是:当评论完以后,页面重新加载,评论区域会自动翻滚到页面最上端,体验很好。

按了comments按钮以后,可以直接跳转到post页面的评论区域,等于是个页中页功能。

链接到博客的评论_post.html

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

user.html 增加评论数

<p><b> 评论数量:</b>{{ user.comments.count() }}.</p>

_macro.html 宏需要加入片断参数

{% macro pagination_widget(pagination,endpoint,fragment='') %}
<ul class="pagination">
<li {% if not pagination.has_prev %}class="disabled" {% endif %}>
<a href="{% if pagination.has_prev %}{{ url_for(endpoint,page = pagination.prev_num,**kwargs) }}{{ fragment }}{% else %}#{% endif %}">
&laquo;
</a>
</li>
{% for p in pagination.iter_pages() %}
{% if p %}
{% if p ==pagination.page %}
<li class="active">
<a href="{{ url_for(endpoint,page=p,**kwargs) }}{{ fragment }}">{{ p }}</a>
</li>
{% else %}
<li>
<a href="{{ url_for(endpoint,page=p,**kwargs) }}{{ fragment }}">{{ p }}</a>
</li>
{% endif %}
{% else %}
<li class="disabled"><a href="#">&hellip;</a></li>
{% endif %}
{% endfor %}
<li {% if not pagination.has_next %}class="disabled" {% endif %}>
<a href="{% if pagination.has_next %}{{ url_for(endpoint,page = pagination.next_num,**kwargs) }}{{ fragment }}{% else %}#{% endif %}">
&raquo;
</a>
</li>
</ul>
{% endmacro %}

管理评论

base.html加入评论管理导航条

{% if current_user.can(Permission.MODERATE_COMMENTS) %}
<li>
<a href="{{ url_for('main.moderate') }}">评论管理</a>
</li>
{% endif %}

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)

moderate.html 评论管理页面模板

{% extends "base.html" %}
{% import '_macros.html' as macros %}
{% block title %}Flasky - 评论管理{% endblock %} {% block page_content %}
<div class="page-header">
<h1>评论管理</h1>
</div>
{% set moderate = True %} # 决定是否渲染评论管理功能
{% include '_comments.html' %}
{% if pagination %}
<div class="pagination">
{% if pagination %}
<div class="pagination">
{{ macros.pagination_widget(pagination, '.moderate') }}
</div>
{% endif %}
</div>
{% endif %}
{% endblock %}

_comments.html 评论正文

 <div class="comment-body">
{% if comment.disabled %}
<p><i>此评论已被管理员禁用</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) }}">恢复</a>
{% else %}
<a class="btn btn-default btn-xs" href="{{ url_for('.moderate_disable',id=comment.id,page=page) }}">禁用</a>
{% endif %}
{% endif %}
</div>

main.views.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)))

Flask 学习 十二 用户评论的更多相关文章

  1. flask学习(十二):for循环遍历

    一. 字典的遍历 语法和python一样,可以使用items().keys().values().iteritems().iterkeys().itervalues() {% for k, v in ...

  2. (转)SpringMVC学习(十二)——SpringMVC中的拦截器

    http://blog.csdn.net/yerenyuan_pku/article/details/72567761 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter, ...

  3. Flask 学习篇二:学习Flask过程中的记录

    Flask学习笔记: GitHub上面的Flask实践项目 https://github.com/SilentCC/FlaskWeb 1.Application and Request Context ...

  4. Scala学习十二——高阶函数

    一.本章要点 在Scala中函数是”头等公民“(可以作为参数,返回值,赋值给其他); 可以创建匿名函数,通常还会交给其他函数; 函数参数可以给出需要稍后执行的行为; 许多集合方法都接受函数参数,将函数 ...

  5. Flask学习之二 模板

    继续学习flask 本部分Miguel Grinberg教程的翻译地址:http://www.pythondoc.com/flask-mega-tutorial/templates.html 英文原文 ...

  6. Flask 学习(二)路由

    Flask  路由 在说明什么是 Flask 路由之前,详细阐述下 Flask “Hello World” 这一 最小应用的代码. Flask “Hello World” from flask imp ...

  7. java web 学习十二(session)

    一.Session简单介绍 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务 ...

  8. Flask 学习 十四 测试

    获取代码覆盖报告 安装代码覆盖工具 pip install coverage manage.py 覆盖检测 COV = None if os.environ.get('FLASK_COVERAGE') ...

  9. Flask 学习 十 博客文章

    提交和显示博客文章 app/models.py 文章模型 class Post(db.Model): __tablename__ = 'posts' id = db.Column(db.Integer ...

随机推荐

  1. 零基础新手学习Java必须知道的市场行情

    Java如今的市场不如从前,竞争很大,工资非常高,标准非常高,想要胜任一份高薪的工作不是那么容易,只有掌握最新的行情才能更好的了解Java,才能更好的在这个领取发展,让新手小白了解Java市场行情如下 ...

  2. 【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)

    [BZOJ1009]GT考试(KMP算法,矩阵快速幂,动态规划) 题面 BZOJ 题解 看到这个题目 化简一下题意 长度为\(n\)的,由\(0-9\)组成的字符串中 不含串\(s\)的串的数量有几个 ...

  3. 【BZOJ5020】【THUWC2017】在美妙的数学王国中畅游(Link-Cut Tree,组合数学)

    [BZOJ5020][THUWC2017]在美妙的数学王国中畅游(Link-Cut Tree,组合数学) 题解 Description 数字和数学规律主宰着这个世界. 机器的运转, 生命的消长, 宇宙 ...

  4. 【BZOJ2816】【ZJOI2012】网络(Link-Cut Tree)

    [BZOJ2816][ZJOI2012]网络(Link-Cut Tree) 题面 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相 ...

  5. tar命令核心应用案列及多重参数和find组合应用

    tar zcvf 压缩包 文件 打包:尽量切换到打包目录的上级目录,然后用相对路径打包 tar zcvf [随意路径] /框 [相对路径]  一堆苹果 tar tf 查看内容 -z --gzip -- ...

  6. Node.js 部署免费/自动续订 HTTPS

    随着互联网快速发展,互联网信息安全越来越受到大家重视,HTTPS 应该是近两年各大厂商都在尽力普及的技术之一.国内大厂基本上已经全面普及了 HTTPS. 本文首发于我的个人网站:听说 - https: ...

  7. PHPStorm 最新版 去掉参数提示 parameter name hints

    最新的phpstorm有个默认开启的参数名和类型提示功能, 这对于开发有很大的帮助,但是对于有些同学来说,刚开始可鞥不是很习惯,所以就需要把他给关闭. 在 配置面板中搜索 parameter name ...

  8. c# winform中的一段代码赏析

    我遇到了一个bug,是客户测试我们的产品,报出来的,而且有异常信息文件,这对于定位问题,很有帮助. 我找到源码看了下,bug还无法重现.于是我随便点点客户端,经过了几次调试,结果报出错误来了.客户端界 ...

  9. Android OpenGL ES 开发(十): 通过GLES20与着色器交互

    1. 获取着色器程序内成员变量的id(句柄.指针) GLES20.glGetAttribLocation方法:获取着色器程序中,指定为attribute类型变量的id. GLES20.glGetUni ...

  10. 原生js移动端滑动事件

    移动端触屏滑动的效果其实就是图片轮播,在PC的页面上很好实现,绑定click和mouseover等事件来完成.但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch事件 ...