在沒有互聯網的年代,咱們用日記來記錄天天的心得體會。小的時候我有一個帶鎖的日記本,生怕被別人看見裏面寫了啥,鑰匙藏得那叫一個絕。html
如今時代變了,網絡版的日記本:博客,卻恨不得越多人看越好。python
別人看完你寫的深度好文,不免也想高談闊論一番,這就是「評論」功能。git
本章將要編寫的評論模塊,幾乎沒有新的知識點,而是將前面章節內容的綜合應用。程序員
強烈建議讀者自行嘗試編寫這部份內容,測試本身的知識掌握程度。github
評論是一個相對獨立的功能,所以新建一個評論的app:django
(env) E:\django_project\my_blog > ppython manage.py startapp comment
有的人以爲奇怪,沒有博文就沒有評論,爲何說評論是「獨立」的功能?那是由於不只博文能夠評論,照片、視頻甚至網站自己均可以「被評論」。將其封裝成單獨的模塊方便之後的擴展。bash
確認app建立成功後,記得在settings.py
中註冊:服務器
my_blog/settings.py ... INSTALLED_APPS = [ ... 'comment', ] ... TIME_ZONE = 'Asia/Shanghai' ...
由於咱們想顯示發表評論的時間,修改時區設置TIME_ZONE
爲上海的時區。網絡
而後在my_blog/urls.py
中註冊根路由:app
my_blog/urls.py ... urlpatterns = [ ... # 評論 path('comment/', include('comment.urls', namespace='comment')), ] ...
首先編寫評論的模型:
comment/models.py from django.db import models from django.contrib.auth.models import User from article.models import ArticlePost # 博文的評論 class Comment(models.Model): article = models.ForeignKey( ArticlePost, on_delete=models.CASCADE, related_name='comments' ) user = models.ForeignKey( User, on_delete=models.CASCADE, related_name='comments' ) body = models.TextField() created = models.DateTimeField(auto_now_add=True) class Meta: ordering = ('created',) def __str__(self): return self.body[:20]
模型中共有2個外鍵:
article
是被評論的文章user
是評論的發佈者別忘了每次新增、修改Model後,必須數據遷移。
提示:你必須先在setting.py中註冊app,這個app中的數據遷移才能生效
用戶提交評論時會用到表單,所以新建表單類:
comment/forms.py from django import forms from .models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ['body']
由於模型中的2個外鍵將經過視圖邏輯自動填寫,因此這裏只須要提交body
就足夠了。
在comment app中新建路由文件:
comment/urls.py from django.urls import path from . import views app_name = 'comment' urlpatterns = [ # 發表評論 path('post-comment/<int:article_id>/', views.post_comment, name='post_comment'), ]
評論必須關聯在某篇具體的博文裏,所以傳入博文的id
,方便後續調用。
post_comment()
視圖還沒寫,先取個名字佔位置。
評論的視圖函數以下:
comment/views.py from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.http import HttpResponse from article.models import ArticlePost from .forms import CommentForm # 文章評論 @login_required(login_url='/userprofile/login/') def post_comment(request, article_id): article = get_object_or_404(ArticlePost, id=article_id) # 處理 POST 請求 if request.method == 'POST': comment_form = CommentForm(request.POST) if comment_form.is_valid(): new_comment = comment_form.save(commit=False) new_comment.article = article new_comment.user = request.user new_comment.save() return redirect(article) else: return HttpResponse("表單內容有誤,請從新填寫。") # 處理錯誤請求 else: return HttpResponse("發表評論僅接受POST請求。")
代碼中有2個新面孔。
get_object_or_404()
:它和Model.objects.get()
的功能基本是相同的。區別是在生產環境下,若是用戶請求一個不存在的對象時,Model.objects.get()
會返回Error 500
(服務器內部錯誤),而get_object_or_404()
會返回Error 404
。相比之下,返回404錯誤更加的準確。
redirect()
:返回到一個適當的url中:即用戶發送評論後,從新定向到文章詳情頁面。當其參數是一個Model對象時,會自動調用這個Model對象的get_absolute_url()
方法。所以接下來立刻修改article
的模型。
實際上以前的章節已經用過
redirect()
了。功能是相同的,實現上略有區別。
按照上面說的,在文章模型中添加get_absolute_url()
方法:
article/models.py ... # 記得導入 from django.urls import reverse class ArticlePost(models.Model): ... # 獲取文章地址 def get_absolute_url(self): return reverse('article:article_detail', args=[self.id])
經過reverse()
方法返回文章詳情頁面的url,實現了路由重定向。
評論模塊須要在文章詳情頁面展現,因此必須把評論模塊的上下文也傳遞到模板中。
所以修改article/views.py
中的article_detail()
:
article/views.py ... from comment.models import Comment def article_detail(request, id): # 已有代碼 article = ArticlePost.objects.get(id=id) # 取出文章評論 comments = Comment.objects.filter(article=id) ... # 添加comments上下文 context = { 'article': article, 'toc': md.toc, 'comments': comments } ...
filter()
能夠取出多個知足條件的對象,而get()
只能取出1個,注意區分使用
到最後一步了,堅持。全部後臺的功能已經寫完了,就差把全部這些展示到頁面中了。
修改文章詳情頁面:
templates/article/detail.html ... <div class="col-9"> ... <!-- 已有代碼,文章正文 --> <div class="col-12"> ... </div> <!-- 發表評論 --> <hr> {% if user.is_authenticated %} <div> <form action="{% url 'comment:post_comment' article.id %}" method="POST" > {% csrf_token %} <div class="form-group"> <label for="body"> <strong> 我也要發言: </strong> </label> <textarea type="text" class="form-control" id="body" name="body" rows="2"></textarea> </div> <!-- 提交按鈕 --> <button type="submit" class="btn btn-primary ">發送</button> </form> </div> <br> {% else %} <br> <h5 class="row justify-content-center"> 請<a href="{% url 'userprofile:login' %}">登陸</a>後回覆 </h5> <br> {% endif %} <!-- 顯示評論 --> <h4>共有{{ comments.count }}條評論</h4> <div> {% for comment in comments %} <hr> <p> <strong style="color: pink"> {{ comment.user }} </strong> 於 <span style="color: green"> {{ comment.created|date:"Y-m-d H:i:s" }} </span> 時說: </p> <pre style="font-family: inherit; font-size: 1em;"> {{ comment.body }}</pre> {% endfor %} </div> </div> <!-- 目錄 --> <div class="col-3 mt-4"> ... </div> ...
action
指定數據提交到哪一個url中comments.count
是模板對象中內置的方法,對包含的元素進行計數|date:"Y-m-d H:i:s"
:管道符你已經很熟悉了,用於給對象「粘貼」某些屬性或功能。這裏用於格式化日期的顯示方式。請嘗試修改其中的某些字符試試效果。<pre>
定義預格式化的文本,在咱們的項目中最關鍵的做用是保留空格和換行符。該標籤會改變文字的字體、大小等,所以用style
屬性從新定義相關內容。嘗試將<pre>
替換爲div
,輸入多行文本試試效果。
以前說代碼最好不要複製粘貼,不然有些「小坑」你是留意不到的。好比在
<pre>
標籤中的文本千萬不能縮進。
又到了激動人心的測試環節了。
登陸本身的帳戶,進入某個文章詳情頁面,發現已經能夠進行留言了:
若是退出登陸,顯示提示語:
點擊登陸就回到登陸頁面。
評論模塊的發佈、展現功能就搞定了。
數據的刪、改功能咱們已經作過不少遍,這裏不打算再贅述了。
評論一樣也能夠支持Markdown語法,或者插入Emoji表情符號。
讀者能夠本身去實現感興趣的功能。
有些網站乾脆就沒有刪除、更新評論的功能。由於對小站來講,這些功能用到的次數太少太少了,不如把精力用在更有價值的地方去。好比 個人博客就沒有。還有的網站提供軟刪除,刪除後僅僅是不顯示而已,實際上數據還存在。
具體應該如何作,都以你的喜愛而定。
本章實現了發表評論、展現評論的功能。像開頭說的同樣,本章的內容是前面所學章節的綜合。
若是你沒有看本章代碼,而是徹底靠本身完成了評論功能,那麼恭喜你得到了「Django入門程序員」的稱號!不要小看「入門」兩字,萬事開頭難嘛。
轉載請註明出處。