用django搭建自己的博客(四)-設置評論(轉)

使用高級特性來優化你的博客

在上一章中,你創建了一個基礎的博客應用。現在你將要改造它成為一個功能更加齊全的博客,利用一些高級的特性例如添加評論,給帖子打上tag,檢索出相似的帖子。在本章中,你將會學習以下幾點:

  • 通過models創建表單
  • 構建復雜的QuerySets

現在我們準備為博客創建一個評論系統,這樣用戶可以在帖子上進行評論。你需要做到以下幾點來創建一個評論系統:

  • 創建一個modle保存評論
  • 創建一表單用來提交平路你和驗證輸入的數據
  • 添加一個view來處理表單和保存新的評論到數據庫中
  • 編輯帖子的詳情template來展示評論列表以及用來添加新評論的表單

首先,讓我們創建一個model來存儲評論。打開你博客應用下的models.py文件添加如下代碼:

class Comment(models.Model):
    name = models.CharField(max_length=80)
    post = models.ForeignKey(Post, related_name='comments')
    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 'Comment by {} on {}'.format(self.name, self.post)

以上就是我們的Comment model。它包含了一個外鍵用來關聯一個單獨的帖子。在Comment model中定義多對單的關系是因為每一條評論只能在一個帖子下生成,而每一個帖子又可能包含多個評論。related_name屬性允許我們命名這個屬性這樣我們就可以使用這個關系從有關聯的對象來讀取這兒。定義好這個之后,我們可以從一條評論來取到對應的帖子通過使用 comment.post和取回一個帖子所有的評論通過使用post.comments.all(。如果你沒有定義related_name屬性,Django會使用這個model的命名加上_set(例如:comment_set)來命名關聯對象讀取這兒的manager。

你可以學習更多關于多對單的關系通過訪問 多對單的關系

我們有包含一個active布爾字段用來手動使不好的評論無效不展示。我們使用created字段使評論默認根據創建時間來進行排序。

你剛創建的這個新的Comment model并沒有同步到數據庫中。運行以下命令通過新的model生成一個新的數據遷移,并創建數據庫:

python manage.py makemigrations blog
python manage.py migrate

添加站點管理

現在,我們可以添加我們新的model到管理站點中通過簡單的接口來管理評論。打開博客應用下的admin.py文件,添加如下內容:

from .models import Post, Comment

class CommentAdmin(admin.ModelAdmin):
    list_display = ('name', 'email', 'post', 'created', 'active')
    list_filter = ('active', 'created', 'updated')
    search_fields = ('name', 'email', 'body')

admin.site.register(Comment, CommentAdmin)

訪問 http://127.0.0.1:8000/admin/ 會看多多出一個 Comments

通過models創建表單

我們仍然需要創建一個表單可以讓我們的用戶在博客帖子下進行評論。請記住,Django有兩個用來創建表單的基礎類:Form和ModelForm。你已經使用過前者可以讓用戶通過email來分享帖子。在下面的例子中,你將需要使用ModelForm因為你必須從你的Comment model中創建一個動態的表單。編輯博客應用下的forms.py,添加如下代碼:

from .models import Comment

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ('name', 'email', 'body')

從model中創建表單,我們只需要在這個表單的Meta類中聲明使用哪個model來構建表單。Django將會解析model并為我們動態的創建表單。每一種model字段類型都有對應的默認表單字段類型。默認的,Django創建的表單包含model中包含的每個字段。當然,你可以明確的告訴框架你想在你的表單中包含哪些字段通過使用fields列,或者定義哪些字段你不需要的通過使用exclude列。對于我們的CommentForm,我們在表單中只需要name,email,和body字段,因為我們只需要用到這3個字段讓我們的用戶來填寫。

在views中操作ModelForms

我們會使用帖子的詳情view來實例化表單,能更簡單的處理它。編輯models.py文件,導入Comment modle和CommentForm表單,并且修改post_detail view如下所示:

from .forms import EmailPostForm, CommentForm
from django.views.generic import ListView

class PostListView(ListView):
    queryset = Post.published.all()
    context_object_name = 'posts'
    paginate_by = 3
    template_name = 'blog/post/list.html'

def post_detail(request, year, month, day, post):
   post = get_object_or_404(Post, slug=post,
                                  status='published',
                                  publish__year=year,
                                  publish__month=month,
                                  publish__day=day)
   # List of active comments for this post
   comments = post.comments.filter(active=True)

   if request.method == 'POST':
       comment_form = CommentForm(data=request.POST)
       if comment_form.is_valid():
           new_comment = comment_form.save(commit=False)
           new_comment.post = post
           new_comment.save()
   else:
       comment_form = CommentForm()
   return render(request,'blog/post/detail.html',{'post': post, 'comments': comments, 'comment_form': comment_form})

讓我們來回顧下我們剛才對對我的view添加了哪些操作。我們使用post_detail view來顯示帖子和對應的評論。我們添加了一個QuerySet來顯示這個帖子所有有效的評論:

comments = post.comments.filter(active=True)

我們從post對象開始構建這個QuerySet。使用在Comment model中通過related_name屬性定義的關系啦返回所有有關系的對象給comments*。

我們還在這個view中讓我們的用戶添加一條新的評論。如果調用這個view通過GET請求,就我們創建了一個表單實例通過使用comment_fomr = commentForm()
。如果請求是一個已經完成驗證的POST,我們實例化表單來使用提交的數據并且驗證數據通過使用is_valid()方法。如果這個表單是無效的,我們會在template中渲染驗證錯誤的信息。如果表單通過驗證,我們會做以下的操作:

  1. 我們創建一個新的Comment對象通過調用這個表單的save()方法,如下所示:
new_comment = comment_form.save(commit=False)

saven()方法創建了一個model的實例用來保存表單的數據到數據庫中。如果你調用這個方法通過設置comment=False
,你創建的model實例不會即時保存到數據中。這是非常方便的當你想在最終保存之前修改這個model對象,我們接下來將做這一步驟。save()方法是給ModelForm用的,但不是給表單實例們用的,因為它們沒有關聯上任何model。

  1. 我們分配一個帖子給我們剛才創建的評論:
new_comment.post = post

通過以上動作,我們指定新的評論是屬于分配的帖子。
3.我們保存新的評論到數據庫,如下所示:

new_comment.save()

我們的view已經準備好顯示和處理新的評論了。

在帖子詳情template中添加評論

我們為帖子創建了一個管理評論的功能。現在我們需要修改我們的post_detail.html template來適應這個功能,通過做到以下步驟:

  • 顯示這個帖子的評論總數
  • 顯示評論的列
  • 顯示一個表單給用戶來添加新的評論

首先,我們來添加評論的總數。打開blog/detail.html template在content區塊中添加如下代碼:

    {% with comments.count as total_comments %}
        <h2>
            {{ total_comments }} comment{{ total_comments|pluralize }}
        </h2>
    {% endwith %}

我們在template中使用Django ORM執行comments.count() QuerySet。注意,在Django template語言中調用方法時不使用圓括號。{% with %} tag允許我們分配一個值給新的變量,這個變量可以一直使用直到遇到{% endwith %}

{% whti %} template tag是非常有用的可以避開直接使用數據庫或花費大量的時間在處理復雜的方法。

我們使用pluralize template filter在單詞comment的后面展示total_comments的復數形式。Template filters使輸入的變量值經過應用然后返回計算后的值。我們將會更多的討論tempalte filters在第三章 擴展你的博客應用中。

這pluralize template filter 會在值的末尾顯示一個"s"如果值不為 1。在之前的文本將會渲染成類似: 0 comments, 1 comment 或者 N comments。Django內置大量的template tags 和 filters來幫助你通過各種方法展示各類信息。

現在,讓我們加入評論列。在blog/detail.html中之前的代碼后面加入以下內容:

    {% 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>There are no comments yet.</p>
    {% endfor %}

我們使用{% for %}template tag來循環所有的評論。我們會顯示一個默認的信息如果comments列為空,告訴我們的用戶這篇帖子還沒有任何評論。我們通過使用{{ forloop.counter }}變量來枚舉評論,該變量包含在每次迭代的循環計數中。之后我們顯示發送評論的用戶名,日期,和評論的內容。

最后,你需要渲染表單或者顯示一條成功的信息來代替表單當表單提交成功后。在之前的代碼后面添加如下內容:

    {% if new_comment %}
        <h2>Your comment has been added.</h2>
    {% else %}
        <h2>Add a new comment</h2>
        <form action="." method="post">
            {{ comment_form.as_p }}
            {% csrf_token %}
            <p><input type="submit" value="Add comment"></p>
        </form>
    {% endif %}

這段代碼非常簡潔明了:如果存在new_comment對象,我們會展示一條成功信息因為成功創建了一條新評論。否則,我們通過一個段落<p>
元素渲染表單中每一個字段,并且表明這個POST請求包含有CSRF標記。在瀏覽器中打開 http://127.0.0.1:8000/blog/ 然后點擊任意一篇帖子的標題進入它的詳情頁面。你會看到如下頁面展示:

comments

郵箱一定要是正確格式,不然提交沒反應。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容