摘要:創建了數據庫模型就要遷移數據庫,遷移數據庫的命令也在前面講過。如果表單對應有一個數據庫模型例如這里的評論表單對應著評論模型,那么使用類會簡單很多,這是為我們提供的方便。表明這個表單對應的數據庫模型是類。
創建評論應用
相對來說,評論其實是另外一個比較獨立的功能。Django 提倡,如果功能相對比較獨立的話,最好是創建一個應用,把相應的功能代碼寫到這個應用里。我們的第一個應用叫 blog,它里面放了展示博客文章列表和細節等相關功能的代碼。而這里我們再創建一個應用,名為 comments,這里面將存放和評論功能相關的代碼。首先激活虛擬環境,然后輸入如下命令創建一個新的應用:
python manage.py startapp comments
我們可以看到生成的 comments 應用目錄結構和 blog 應用的目錄是類似的。關于創建應用以及 Django 的目錄結構在 建立 Django 博客應用 中已經有過介紹。創建新的應用后一定要記得在 settings.py 里注冊這個應用,Django 才知道這是一個應用。
blogproject/settings.py ... INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "blog", "comments", # 注冊新創建的 comments 應用 ] ...設計評論的數據庫模型
用戶評論的數據必須被存儲到數據庫里,以便其他用戶訪問時 Django 能從數據庫取回這些數據然后展示給訪問的用戶,因此我們需要為評論設計數據庫模型,這和設計文章、分類、標簽的數據庫模型是一樣的,如果你忘了怎么做,再回顧一下 創建 Django 博客的數據庫模型 中的做法。我們的評論模型設計如下(評論模型的代碼寫在 commentmodels.py 里):
comments/models.py from django.db import models from django.utils.six import python_2_unicode_compatible # python_2_unicode_compatible 裝飾器用于兼容 Python2 @python_2_unicode_compatible class Comment(models.Model): name = models.CharField(max_length=100) email = models.EmailField(max_length=255) url = models.URLField(blank=True) text = models.TextField() created_time = models.DateTimeField(auto_now_add=True) post = models.ForeignKey("blog.Post") def __str__(self): return self.text[:20]
這里我們會保存評論用戶的 name(名字)、email(郵箱)、url(個人網站),用戶發表的內容將存放在 text 字段里,created_time 記錄評論時間。最后,這個評論是關聯到某篇文章(Post)的,由于一個評論只能屬于一篇文章,一篇文章可以有多個評論,是一對多的關系,因此這里我們使用了 ForeignKey。關于 ForeKey 我們前面已有介紹,這里不再贅述。
同時注意我們為 DateTimeField 傳遞了一個 auto_now_add=True 的參數值。auto_now_add 的作用是,當評論數據保存到數據庫時,自動把 created_time 的值指定為當前時間。created_time 記錄用戶發表評論的時間,我們肯定不希望用戶在發表評論時還得自己手動填寫評論發表時間,這個時間應該自動生成。
創建了數據庫模型就要遷移數據庫,遷移數據庫的命令也在前面講過。在虛擬環境下分別運行下面兩條命令:
python manage.py makemigrations python manage.py migrate評論表單設計
這一節我們將學習一個全新的 Django 知識:表單。那么什么是表單呢?基本的 HTML 知識告訴我們,在 HTML 文檔中這樣的代碼表示一個表單:
為什么需要表單呢?表單是用來收集并向服務器提交用戶輸入的數據的。考慮用戶在我們博客網站上發表評論的過程。當用戶想要發表評論時,他找到我們給他展示的一個評論表單(我們已經看到在文章詳情頁的底部就有一個評論表單,你將看到表單呈現給我們的樣子),然后根據表單的要求填寫相應的數據。之后用戶點擊評論按鈕,這些數據就會發送給某個 URL。我們知道每一個 URL 對應著一個 Django 的視圖函數,于是 Django 調用這個視圖函數,我們在視圖函數中寫上處理用戶通過表單提交上來的數據的代碼,比如驗證數據的合法性并且保存數據到數據庫中,那么用戶的評論就被 Django 后臺處理了。如果通過表單提交的數據存在錯誤,那么我們把錯誤信息返回給用戶,并在前端重新渲染,并要求用戶根據錯誤信息修正表單中不符合格式的數據,再重新提交。
Django 的表單功能就是幫我們完成上述所說的表單處理邏輯,表單對 Django 來說是一個內容豐富的話題,很難通過教程中的這么一個例子涵蓋其全部用法。因此我們強烈建議你在完成本教程后接下來的學習中仔細閱讀 Django 官方文檔關于 表單 的介紹,因為表單在 Web 開發中會經常遇到。
下面開始編寫評論表單代碼。在 comments 目錄下(和 models.py 同級)新建一個 forms.py 文件,用來存放表單代碼,我們的表單代碼如下:
comments/forms.py from django import forms from .models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ["name", "email", "url", "text"]
要使用 Django 的表單功能,我們首先導入 forms 模塊。Django 的表單類必須繼承自 forms.Form 類或者 forms.ModelForm 類。如果表單對應有一個數據庫模型(例如這里的評論表單對應著評論模型),那么使用 ModelForm 類會簡單很多,這是 Django 為我們提供的方便。之后我們在表單的內部類 Meta 里指定一些和表單相關的東西。model = Comment 表明這個表單對應的數據庫模型是 Comment 類。fields = ["name", "email", "url", "text"] 指定了表單需要顯示的字段,這里我們指定了 name、email、url、text 需要顯示。
關于表單進一步的解釋Django 為什么要給我們提供一個表單類呢?為了便于理解,我們可以把表單和前面講過的 Django ORM 系統做類比?;叵胍幌?,我們使用數據庫保存我們創建的博客文章,但是我們從頭到尾沒有寫過任何和數據庫有關的代碼(要知道數據庫自身也有一門數據庫語言),這是因為 Django 的 ORM 系統內部幫我們做了一些事情。我們遵循 Django 的規范寫的一些 Python 代碼,例如創建 Post、Category 類,然后通過運行數據庫遷移命令將這些代碼反應到數據庫。
Django 的表單和這個思想類似,正常的前端表單代碼應該是和本文開頭所提及的那樣,但是我們目前并沒有寫這些代碼,而是寫了一個 CommentForm 這個 Python 類。通過調用這個類的一些方法和屬性,Django 將自動為我們創建常規的表單代碼,接下來的教程我們就會看到具體是怎么做的。
評論視圖函數當用戶提交表單中的數據后,Django 需要調用相應的視圖函數來處理這些數據,下面開始寫我們視圖函數處理邏輯:
comments/views.py from django.shortcuts import render, get_object_or_404, redirect from blog.models import Post from .models import Comment from .forms import CommentForm def post_comment(request, post_pk): # 先獲取被評論的文章,因為后面需要把評論和被評論的文章關聯起來。 # 這里我們使用了 Django 提供的一個快捷函數 get_object_or_404, # 這個函數的作用是當獲取的文章(Post)存在時,則獲取;否則返回 404 頁面給用戶。 post = get_object_or_404(Post, pk=post_pk) # HTTP 請求有 get 和 post 兩種,一般用戶通過表單提交數據都是通過 post 請求, # 因此只有當用戶的請求為 post 時才需要處理表單數據。 if request.method == "POST": # 用戶提交的數據存在 request.POST 中,這是一個類字典對象。 # 我們利用這些數據構造了 CommentForm 的實例,這樣 Django 的表單就生成了。 form = CommentForm(request.POST) # 當調用 form.is_valid() 方法時,Django 自動幫我們檢查表單的數據是否符合格式要求。 if form.is_valid(): # 檢查到數據是合法的,調用表單的 save 方法保存數據到數據庫, # commit=False 的作用是僅僅利用表單的數據生成 Comment 模型類的實例,但還不保存評論數據到數據庫。 comment = form.save(commit=False) # 將評論和被評論的文章關聯起來。 comment.post = post # 最終將評論數據保存進數據庫,調用模型實例的 save 方法 comment.save() # 重定向到 post 的詳情頁,實際上當 redirect 函數接收一個模型的實例時,它會調用這個模型實例的 get_absolute_url 方法, # 然后重定向到 get_absolute_url 方法返回的 URL。 return redirect(post) else: # 檢查到數據不合法,重新渲染詳情頁,并且渲染表單的錯誤。 # 因此我們傳了三個模板變量給 detail.html, # 一個是文章(Post),一個是評論列表,一個是表單 form # 注意這里我們用到了 post.comment_set.all() 方法, # 這個用法有點類似于 Post.objects.all() # 其作用是獲取這篇 post 下的的全部評論, # 因為 Post 和 Comment 是 ForeignKey 關聯的, # 因此使用 post.comment_set.all() 反向查詢全部評論。 # 具體請看下面的講解。 comment_list = post.comment_set.all() context = {"post": post, "form": form, "comment_list": comment_list } return render(request, "blog/detail.html", context=context) # 不是 post 請求,說明用戶沒有提交數據,重定向到文章詳情頁。 return redirect(post)
這個評論視圖相比之前的一些視圖復雜了很多,主要是處理評論的過程更加復雜。具體過程在代碼中已有詳細注釋,這里僅就視圖中出現了一些新的知識點進行講解。
首先我們使用了 redirect 函數。這個函數位于 django.shortcuts 模塊中,它的作用是對 HTTP 請求進行重定向(即用戶訪問的是某個 URL,但由于某些原因,服務器會將用戶重定向到另外的 URL)。redirect 既可以接收一個 URL 作為參數,也可以接收一個模型的實例作為參數(例如這里的 post)。如果接收一個模型的實例,那么這個實例必須實現了 get_absolute_url 方法,這樣 redirect 會根據 get_absolute_url 方法返回的 URL 值進行重定向。
另外我們使用了 post.comment_set.all() 來獲取 post 對應的全部評論。 Comment 和Post 是通過 ForeignKey 關聯的,回顧一下我們當初獲取某個分類 cate 下的全部文章時的代碼:Post.objects.filter(category=cate)。這里 post.comment_set.all() 也等價于 Comment.objects.filter(post=post),即根據 post 來過濾該 post 下的全部評論。但既然我們已經有了一個 Post 模型的實例 post(它對應的是 Post 在數據庫中的一條記錄),那么獲取和 post 關聯的評論列表有一個簡單方法,即調用它的 xxx_set 屬性來獲取一個類似于 objects 的模型管理器,然后調用其 all 方法來返回這個 post 關聯的全部評論。 其中 xxx_set 中的 xxx 為關聯模型的類名(小寫)。例如 Post.objects.filter(category=cate) 也可以等價寫為 cate.post_set.all()。
綁定 URL視圖函數需要和 URL 綁定,這里我們在 comment 應用中再建一個 urls.py 文件,寫上 URL 模式:
comments/urls.py from django.conf.urls import url from . import views app_name = "comments" urlpatterns = [ url(r"^comment/post/(?P[0-9]+)/$", views.post_comment, name="post_comment"), ]
別忘了給這個評論的 URL 模式規定命名空間,即 app_name = "comments"。
最后要在項目的 blogprokect 目錄的 urls.py 里包含 commentsurls.py 這個文件:
blogproject/urls.py urlpatterns = [ url(r"^admin/", admin.site.urls), url(r"", include("blog.urls")), + url(r"", include("comments.urls")), ]更新文章詳情頁面的視圖函數
我們可以看到評論表單和評論列表是位于文章詳情頁面的,處理文章詳情頁面的視圖函數是 detail,相應地需要更新 detail,讓它生成表單和從數據庫獲取文章對應的評論列表數據,然后傳遞給模板顯示:
blog/views.py import markdown from django.shortcuts import render, get_object_or_404 + from comments.forms import CommentForm from .models import Post, Category def detail(request, pk): post = get_object_or_404(Post, pk=pk) post.body = markdown.markdown(post.body, extensions=[ "markdown.extensions.extra", "markdown.extensions.codehilite", "markdown.extensions.toc", ]) # 記得在頂部導入 CommentForm form = CommentForm() # 獲取這篇 post 下的全部評論 comment_list = post.comment_set.all() # 將文章、表單、以及文章下的評論列表作為模板變量傳給 detail.html 模板,以便渲染相應數據。 context = {"post": post, "form": form, "comment_list": comment_list } return render(request, "blog/detail.html", context=context)在前端渲染表單
使用 Django 表單的一個好處就是 Django 能幫我們自動渲染表單。我們在表單的視圖函數里傳遞了一個 form 變量給模板,這個變量就包含了自動生成 HTML 表單的全部數據。在 detail.html 中通過 form 來自動生成表單。刪掉原來用于占位的 HTML 評論表單代碼,即下面這段代碼:
替換成如下的代碼:
{{ form.name }}、{{ form.email }}、{{ form.url }} 等將自動渲染成表單控件,例如 控件。
{{ form.name.errors }}、{{ form.email.errors }} 等將渲染表單對應字段的錯誤(如果有的話),例如用戶 email 格式填錯了,那么 Django 會檢查用戶提交的 email 的格式,然后將格式錯誤信息保存到 errors 中,模板便將錯誤信息渲染顯示。
顯示評論內容在 detail 視圖函數我們獲取了全部評論數據,并通過 comment_list 傳遞給了模板。和處理 index 頁面的文章列表方式是一樣的,我們在模板中通過 {% for %} 模板標簽來循環顯示文章對應的全部評論內容。
刪掉占位用的評論內容的 HTML 代碼,即如下的代碼:
替換成如下的代碼:
接下來嘗試在詳情頁下的評論表單提交一些評論數據,可以看到詳情頁的評論列表處渲染了你提交的評論數據。
總結本章節的代碼位于:Step12: comments。
如果遇到問題,請通過下面的方式尋求幫助。
在 評論 - 追夢人物的博客 的評論區留言。
將問題的詳細描述通過郵件發送到 djangostudyteam@163.com,一般會在 24 小時內回復。
更多Django 教程,請訪問 追夢人物的博客。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44393.html
摘要:本教程內容已過時,更新版教程請訪問博客開發入門教程。我們的評論表單放在中,評論成功后返回到原始提交頁面。學習小組簡介學習小組是一個促進新手互相學習互相幫助的組織。 本教程內容已過時,更新版教程請訪問: django 博客開發入門教程。 通過前四周的時間我們開發了一個簡單的個人 Blog,前幾期教程地址: 第一周:Django 學習小組:博客開發實戰第一周教程 —— 編寫博客的 Mode...
摘要:本教程內容已過時,更新版教程請訪問博客開發入門教程。我們的評論表單放在中,評論成功后返回到原始提交頁面。學習小組簡介學習小組是一個促進新手互相學習互相幫助的組織。 本教程內容已過時,更新版教程請訪問: django 博客開發入門教程。 通過前四周的時間我們開發了一個簡單的個人 Blog,前幾期教程地址: 第一周:Django 學習小組:博客開發實戰第一周教程 —— 編寫博客的 Mode...
摘要:所以,讓我們再接再厲,進入到博客開發進階教程,學習更多的開發技巧,為博客提供更多的功能吧總結本章節的代碼位于。在已知小問題修正追夢人物的博客的評論區留言。將問題的詳細描述通過郵件發送到,一般會在小時內回復。更多教程,請訪問追夢人物的博客。 在模型中指定排序 為了讓文章(Post)按發布時間逆序排列,即最新發表的文章排在文章列表的最前面,我們對返回的文章列表進行了排序,即各個視圖函數中都...
摘要:而對于標簽來說,一篇文章可以有多個標簽,同一個標簽下也可能有多篇文章,所以我們使用,表明這是多對多的關聯關系。理解多對一和多對多兩種關聯關系我們分別使用了兩種關聯數據庫表的形式和。表明一種一對多的關聯關系。 設計博客的數據庫表結構 博客最主要的功能就是展示我們寫的文章,它需要從某個地方獲取博客文章數據才能把文章展示出來,通常來說這個地方就是數據庫。我們把寫好的文章永久地保存在數據庫里,...
摘要:本教程內容已過時,更新版教程請訪問博客開發入門教程。表示降序排列,默認是升序排列。學習小組簡介學習小組是一個促進新手互相學習互相幫助的組織。我們會將每周的詳細開發文檔和代碼通過郵件列表發出。 本教程內容已過時,更新版教程請訪問: django 博客開發入門教程。 通過前四周的時間我們開發了一個簡單的個人 Blog,教程地址: 第一周:Django 學習小組:博客開發實戰第一周教程 ——...
閱讀 3564·2021-11-16 11:45
閱讀 2099·2021-11-08 13:23
閱讀 2212·2021-10-11 10:59
閱讀 2892·2021-09-27 13:36
閱讀 2481·2019-08-30 15:54
閱讀 2669·2019-08-29 16:58
閱讀 2783·2019-08-29 16:56
閱讀 1342·2019-08-26 13:52