第十三章 用戶評論
允許用戶互動交流時社交博客平臺成功的關(guān)鍵。在本章中常遂,我們將學(xué)習(xí)如何實現(xiàn)用戶評論功能纳令。這一技術(shù)可以直接應(yīng)用到大型的社交程序當(dāng)中。
準(zhǔn)備評論數(shù)據(jù)庫
評論和普通博客文章沒有什么不同,同樣有內(nèi)容平绩,作者和時間戳圈匆,在這個部分中都是使用了Markdown語法寫的。圖13-1展示了數(shù)據(jù)庫中comments表和其他表的關(guān)系:
評論是針對特定的博客文章的捏雌,所以在posts表中需要定義一個一對多關(guān)系跃赚。我們將使用這個關(guān)系來獲取指定文章的所有相關(guān)評論列表。
comment表和users表組成了一對多的關(guān)系性湿。通過這一關(guān)系我們可以獲取某一用戶的所有評論纬傲,統(tǒng)計他寫了多少評論,等一些信息都可以展示在用戶屬性頁面上肤频。Comment模型的定義如下(13-1)所示:
Example 13-1. app/models.py: Comment model
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)
comment模型的屬性跟post模型基本一樣叹括,但添加了一個disabled字段,通過設(shè)置它的boolean值宵荒,版主可以禁止或屏蔽攻擊性和不合適的言論汁雷。就像對博客文章的處理那樣,評論也定義了一個事件觸發(fā)器报咳,當(dāng)body字段變更時摔竿,就會自動把markdown文本轉(zhuǎn)換成HTML。這一流程跟我們在第十一章中對博客文章的處理一樣少孝,但由于評論的內(nèi)容通常較短,markdown轉(zhuǎn)換過程中允許的html標(biāo)記更少熬苍,段落標(biāo)記被移除了稍走,只留下了字符格式化標(biāo)記。
為了完成數(shù)據(jù)庫更改柴底,User和Post模型也都需要和comments表建立一對多關(guān)系婿脸,如例子13-2所示:
Example 13-2. app/models/user.py: One-to-many relationships from users and posts to 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')
提交并顯示Comment
在本程序中,我們在第十一章中通過添加永久鏈接柄驻,在單獨頁面中顯示了博客文章評論狐树,評論也在這一頁面顯示。同時鸿脓,這頁上也包含了一個表單用來提交評論抑钟。例子13-3顯示了用來輸入評論的web表單——只包含一個簡單的文本域和一個提交按鈕。
Example 13-3. app/main/forms.py: Comment input form
class CommentForm(Form):
body = StringField('', validators=[Required()])
submit = SubmitField('Submit')
例子13-4展示了更新后的路由設(shè)置野哭,通過/post/<int:id>支持評論
Example 13-4. app/main/views.py: Blog post comments support
@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)
該視圖函數(shù)實例化評論表單并將其發(fā)送到post.html模板進(jìn)行顯示在塔。當(dāng)提交表單時,加入一個新評論的邏輯流程類似于對博客文章的處理拨黔。如同在Post例子中那樣蛔溃,評論的author不能直接設(shè)置成current_user,因為這個變量是一個上下文代理對象。表達(dá)式current_user._get_current_object()返回的是實際的User對象贺待。