3既然是博客,那肯定就有留言評論系統.在這一章就來建立一個評論系統.
1 創建一個模型來保存評論
2 創建一個表單來提交評論並且驗證輸入的數據
3 添加一個視圖函數來處理表單和保存新的評論到數據庫
4 編輯帖子模板來展示評論列表以及用來添加新評論的表單
首先來創建一個模型來存儲評論
class Comment(models.Model):
post=models.ForeignKey(Post,related_name='comments')
name=models.CharField(max_length=80)
email=models.EmailField()
body=models.TextField()
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
active=models.BooleanField(default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comments by {} on {}'.format(self.name,self.post)
這就是我們增加評論的模型,其中最關鍵的是post,通過ForeignKey將Comment和Post關聯了起來,關聯關系是多對一,原因是一個博客是有多個評論的.定義好之后,我們就可以通過commens.post來取得對應的帖子.以及通過postcomments.all()來取回一個帖子所有的評論.如果你沒有定義related_name屬性,Django會使用這個模型(model)的名稱加上*_set*(在這里是:comment_set)來命名從相關聯的對象反向定位到這個對象的manager。
接下來完成數據遷移
zhf@zhf-maple:~/py_prj/mysite$ python manage.py makemigrations blog
Migrations for 'blog':
blog/migrations/0002_auto_20180303_1216.py
- Create model Comment
- Alter field author on post
- Alter field body on post
- Alter field created on post
- Alter field publish on post
- Alter field status on post
- Alter field title on post
- Alter field updated on post
- Add field post to comment
zhf@zhf-maple:~/py_prj/mysite$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0002_auto_20180303_1216... OK
同步增加一個評論的管理並在后台進行注冊admin.site.register(Comment,CommentAdmin)
class CommentAdmin(admin.ModelAdmin):
list_display = ('name','email','post','created','active')
list_filter = ('active','created','updated')
search_fields = ('name','email','body')
創建表單:
在這里的表單和前面的郵件分享不太一樣,這里通過模型來創建表單
from .models import Comment
class CommentsForm(forms.ModelForm):
class Meta:
model=Comment
fields=('name','email','body')
根據模型(model)創建表單,我們只需要在這個表單的Meta類里表明使用哪個模型(model)來構建表單。Django將會解析model並為我們動態的創建表單。每一種模型(model)字段類型都有對應的默認表單字段類型。表單驗證時會考慮到我們定義模型(model)字段的方式。Django為模型(model)中包含的每個字段都創建了表單字段。然而,使用fields 列表你可以明確的告訴框架你想在你的表單中包含哪些字段,或者使用exclude 列表定義你想排除在外的那些字段。對於我們的CommentForm來說,我們在表單中只需要name,email,和body字段,因為我們只需要用到這3個字段讓我們的用戶來填寫。
視圖中操作ModelForm
根據模型
def post_list_page(request):
object_list = Post.objects.all()
paginator = Paginator(object_list, 1) # 3 posts in each page
page = request.GET.get('page')
new_comment = None
try:
posts = paginator.page(page)
comments=posts.object_list[0].comments.filter()
except PageNotAnInteger:
posts = paginator.page(1)
comments = posts.object_list[0].comments.filter()
except EmptyPage:
posts = paginator.page(paginator.num_pages)
id = posts.object_list[0].id
post = get_object_or_404(Post, id=id, status='published')
if request.method == 'POST':
comment_form = CommentsForm()
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
else:
comment_form = CommentsForm()
return render(request,
'post/list.html',
{'page': page,
'posts': posts,
'comments':comments,
'new_comment': new_comment,
'comment_form': comment_form,
})
1 通過comments=posts.object_list[0].comments.filter()得到每個博客對應的評論實例
2 id = posts.object_list[0].id得到每個博客實例的id,並通過id得到Post實例
3 通過上傳的CommentsForm表單數據將評論和博客連接起來
(1)我們通過調用這個表單的save()方法創建一個新的Comment對象
new_comment = comment_form.save(commit=False)
Save()方法創建了一個表單鏈接的model的實例,並將它保存到數據庫中。如果你調用這個方法時設置commit=False,你創建的模型(model)實例不會即時保存到數據庫中。當你想在最終保存之前修改這個model對象會非常方便,我們接下來將做這一步驟。save()方法是給ModelForm用的,而不是給Form實例用的,因為Form實例沒有關聯上任何模型(model)
為剛才的評論分配一個帖子
new_comment.post = post
(3) 最后,我們用下面的代碼將新的評論保存到數據庫中:
new_comment.save()
更新模板
既然帖子有了評論功能,現在我們需要修改我們的list模板來適應這個功能。需要呈現如下功能
1 評論總數
2 顯示評論的列表
3 顯示一個表單給用戶來添加新的評論
前面視圖傳遞的comments參數。通過with comments.count as total_comments語句將評論的個數傳遞給total_comments.這樣就能顯示具體有多少個評論
{% with comments.count as total_comments %}
<h2>
{{ total_comments }} comment{{ total_comments|pluralize }}
現在加入評論列表我們使用{% for %}模板(template)標簽(tag)來循環所有的評論。如果comments列為空我們會顯示一個默認的信息,告訴我們的用戶這篇帖子還沒有任何評論。我們使用 {{ forloop.counter }}變量來枚舉所有的評論,在每次迭代中該變量都包含循環計數。之后我們顯示發送評論的用戶名,日期,和評論的內容。
{% for comment in comments %}
<div class="comment">
<p class="info">
Comment {{ forloop.counter }} by {{ comment.name }}
{{ comment.created }}
</p>
{{ comment.body|linebreaks }}
</div>
{% empty %}
<p>還沒有評論</p>
{% endfor %}
最后,你需要渲染表單或者顯示一條成功的信息來代替之前的內容。在之前的代碼后面添加如下內容
{% if new_comment %}
<h2>Your comment has been added.</h2>
{% else %}
<h2>添加新評論</h2>
<form action="/blog/{{ p.id }}/comment/" method="post">
{{ comment_form.as_p }}
{% csrf_token %}
<input type="submit" value="增加評論">
</form>
{% endif %}
如果new_comment對象存在,我們會展示一條成功信息因為成功創建了一條新評論。否則,我們用段落<p>元素渲染表單中每一個字段
下面來測試下功能:
1 進入博客,此時還沒有評論,因此顯示0個評論。在下面有添加評論的界面
2在評論表單中填入信息,點擊增加評論。成功的話顯示評論已經添加成功的頁面
3 此時在回到帖子的頁面,可以看到添加的評論