評論在資料庫中的表示

由於評論和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)))