Django搭建個人部落格:使用Form表單類發表新文章
前面我們已經學會如何用Markdown語法書寫文章了。
但是還有問題呀。之前寫文章都是在後臺中進行的, 萬一有別的普通使用者也要發表文章怎麼辦?萬一我想拓展些後臺中沒有的提交驗證功能又怎麼辦?
本章即講述如何在前臺中提交新的文章,以便滿足開發者各種各樣的 特殊需求 。
Forms表單類
在HTML中,表單是在 <form>...</form>
中的一些元素 ,它允許訪客做類似輸入文字、選擇選項、操作物件或空間等動作,然後傳送這些資訊到服務端。一些表單介面元素(文字框或複選框)非常簡單並內建在HTML中,而其他會複雜些:像彈出日期選擇等操作控制元件。
處理表單是一件挺複雜的事情。想想看Django的admin,許多不同型別的資料可能需要在一張表單中準備顯示,渲染成HTML,使用方便的介面進行編輯,傳到伺服器,驗證和清理資料,然後儲存或跳過進行下一步處理。
Django的表單功能可以簡化上述工作的大部分內容,並且也能比大多數程式員自己編寫程式碼去實現來的更安全。
Django表單系統的核心元件是 Form
類 ,它能夠描述一張表單並決定它如何工作及呈現。
要使用 Form
類也很簡單,需要在 article/
中建立 forms.py
檔案,並寫入如下程式碼:
article/forms.py # 引入表單類 from django import forms # 引入文章模型 from .models import ArticlePost # 寫文章的表單類 class ArticlePostForm(forms.ModelForm): class Meta: # 指明資料模型來源 model = ArticlePost # 定義表單包含的欄位 fields = ('title', 'body') 複製程式碼
程式碼中 ArticlePostForm
類繼承了Django的表單類 forms.ModelForm
,並在類中定義了內部類 class Meta
(之前提到過,還記得嗎),指明瞭資料模型的來源,以及表單中應該包含資料模型的哪些欄位。
在 ArticlePost
模型中, created
和 updated
欄位為自動生成,不需要填入; author
欄位暫時固定為id=1的管理員使用者,也不用填入;剩下的 title
和 body
就是表單需要填入的內容了。
接下來,改寫 article/views.py
,新增一個檢視函式以處理寫文章的請求:
article/views.py ... # 引入redirect重定向模組 from django.shortcuts import render, redirect # 引入HttpResponse from django.http import HttpResponse # 引入剛才定義的ArticlePostForm表單類 from .forms import ArticlePostForm # 引入User模型 from django.contrib.auth.models import User ... # 寫文章的檢視 def article_create(request): # 判斷使用者是否提交資料 if request.method == "POST": # 將提交的資料賦值到表單例項中 article_post_form = ArticlePostForm(data=request.POST) # 判斷提交的資料是否滿足模型的要求 if article_post_form.is_valid(): # 儲存資料,但暫時不提交到資料庫中 new_article = article_post_form.save(commit=False) # 指定資料庫中 id=1 的使用者為作者 new_article.author = User.objects.get(id=1) # 將新文章儲存到資料庫中 new_article.save() # 完成後返回到文章列表 return redirect("article:article_list") # 如果資料不合法,返回錯誤資訊 else: return HttpResponse("表單內容有誤,請重新填寫。") # 如果使用者請求獲取資料 else: # 建立表單類例項 article_post_form = ArticlePostForm() # 賦值上下文 context = { 'article_post_form': article_post_form } # 返回模板 return render(request, 'article/create.html', context) 複製程式碼
分析一下上面的程式碼。當檢視函式接收到一個客戶端的 request
請求時,首先根據 request.method
判斷使用者是要 提交資料(POST)、還是要獲取資料(GET) :
-
如果使用者是 提交資料 ,將POST給伺服器的表單資料賦於
article_post_form
例項。-
然後使用Django內建的方法
.is_valid()
判斷提交的資料是否滿足模型的要求。-
如果 滿足要求 ,儲存表單中的資料(但是
commit=False
暫時不提交到資料庫,因為author
還未指定),並指定author
為id=1的管理員使用者。然後提交到資料庫,並通過redirect
返回文章列表。redirect
可通過url地址的名字,反向解析到對應的url。 -
如果 不滿足要求 ,則返回一個字串**"表單內容有誤,請重新填寫。"**,告訴使用者出現了什麼問題。
-
-
-
如果使用者是 獲取資料 ,則返回一個空的表單類物件,提供給使用者填寫。
其實邏輯並不複雜,不明白的讀者請逐句理解。
**這裡特別提醒Django中的縮排不能夠空格和tab鍵混用,否則會報錯。**由於不同的編輯器對tab的顯示不盡相同,因此你應該堅持使用空格鍵縮排。
寫好檢視之後,就需要寫模板檔案了。在 templates/article/
中建立 create.html
:
templates/article/create.html <!-- extends表明此頁面繼承自 base.html 檔案 --> {% extends "base.html" %} {% load staticfiles %} <!-- 寫入 base.html 中定義的 title --> {% block title %} 寫文章 {% endblock title %} <!-- 寫入 base.html 中定義的 content --> {% block content %} <!-- 寫文章表單 --> <div class="container"> <div class="row"> <div class="col-12"> <br> <!-- 提交文章的表單 --> <form method="post" action="."> <!-- Django中需要POST資料的地方都必須有csrf_token --> {% csrf_token %} <!-- 文章標題 --> <div class="form-group"> <!-- 標籤 --> <label for="title">文章標題</label> <!-- 文字框 --> <input type="text" class="form-control" id="title" name="title"> </div> <!-- 文章正文 --> <div class="form-group"> <label for="body">文章正文</label> <!-- 文字區域 --> <textarea type="text" class="form-control" id="body" name="body" rows="12"></textarea> </div> <!-- 提交按鈕 --> <button type="submit" class="btn btn-primary">完成</button> </form> </div> </div> </div> {% endblock content %} 複製程式碼
html檔案還是一如既往的長。 再重複一次,看不懂html檔案語法也沒有關係,先照著抄一遍,以後再慢慢理解,不影響目前Django的學習。
對其中的新內容進行審視:
-
<form>..</form>
標籤中的內容就是需要提交的表單。method="post"
指定了表單提交的方式為POST(與檢視函式中的request.method
相聯絡);action="."
指定了表單提交的地址為預設的當前url。 - 關於
{% csrf_token %}
,它是Django中一個與網路安全相關的中介軟體驗證。目前我們暫時不去深究它的實現, 只需要知道表單中必須包含它就可以了 ,否則將會得到一個403錯誤。 -
<input>
和<textarea>
標籤中的name=''
屬性指定了當前文字框提交的資料的名稱,它必須與表單類中的欄位名稱對應,否則伺服器無法將欄位和資料正確的對應起來。
最後老規矩,在 article/urls.py
中增加一個寫文章的url地址:
article/urls.py urlpatterns = [ ... # 寫文章 path('article-create/', views.article_create, name='article_create'), ] 複製程式碼
大功告成了,不要著急,先喝口水,萬一有bug又得忙活半天了。 如果報錯也不要慌張,開發過程一定是曲折的,耐心看看Django給出的錯誤提示,線索就在其中。
儲存修改並執行伺服器,位址列中輸入: http://127.0.0.1:8000/article/article-create/
,看到如下介面:

很好,似乎正常工作起來了。接著隨便輸入些Markdown語法的文章,測試功能是否正常:

點選 完成 按鈕後,頁面會回到文章列表:

剛才提交的文章神奇的出現在列表中了。
點選 閱讀本文 按鈕,進入文章詳情頁面:

出現了具有 Markdown 語法的一篇優美的文章。
使用Django編寫部落格是不是非常有成就感呢?
別激動,還有一些收尾工作需要做。
優化寫文章入口
與之前類似,我們需要在導航欄中設定一個 寫文章 的入口,優化使用體驗。
將下列程式碼加入到 templates/header.html
中:
<li class="nav-item"> <a class="nav-link" href="{% url 'article:article_create' %}">寫文章</a> </li> 複製程式碼
讀者是否清楚,上面的程式碼應該放置在什麼位置呢?
儲存後重新整理瀏覽器介面, 導航欄 有了如下變化:

點選 寫文章 按鈕,就可以進入寫新文章的頁面了,從此再也不用手動輸入繁瑣的url地址了。
世界是多麼的美好。