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模型中,createdupdated字段爲自動生成,不需要填入;author字段暫時固定爲id=1的管理員用戶,也不用填入;剩下的titlebody就是表單需要填入的內容了。

接下來,改寫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地址了。

世界是多麼的美好。

總結

本章學習了使用Django的表單類,完成了提交新文章的基本功能。當然目前暫時還沒有真正將文章和登錄的用戶關聯起來;等到學習了用戶管理的知識,再回頭來處理這部分的內容。

下一章繼續學習如何刪除一篇文章。

轉載請告知作者並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章