跳轉至

建立 2026-09-17 更新 2026-09-17

ModelForm

如果表單的欄位剛好對應到某個 Model(例如「新增文章」表單對應 Post 這個 Model),逐一手寫 forms.CharField()forms.DateField() 等於把 Model 的欄位定義重複寫一次。ModelForm 可以直接依 Model 的欄位自動產生表單,並且 save() 之後能直接寫回資料庫,省掉重複定義與手動存檔的步驟。

官方文件:Creating forms from models,裡面也整理了 Form 欄位與 Model 欄位的對應關係、如何覆寫預設欄位。

定義 ModelForm

class Meta 指定要對應的 model,以及要放進表單的 fields

# forms.py
from django import forms

from .models import Post


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ["title", "content"]

fields 也可以寫成 "__all__" 代表包含所有欄位,但正式專案建議明確列出需要的欄位,避免不小心把不該讓使用者填寫的欄位(例如 authorcreated_at)也開放出去。

在 View 中新增與修改資料

新增資料的寫法與一般 Form 幾乎一樣,差別在 form.save() 可以直接把驗證後的資料寫進資料庫,不需要再手動組出 Model 實例:

# views.py
from django.shortcuts import redirect, render

from .forms import PostForm


def create_post(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("post-list")
    else:
        form = PostForm()

    return render(request, "myapp/post_form.html", {"form": form})

修改既有資料時,把要編輯的物件傳進 instance 參數,表單會自動帶入該物件目前的值,save() 也會更新同一筆資料而不是新增一筆:

def update_post(request, pk):
    post = Post.objects.get(pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            form.save()
            return redirect("post-list")
    else:
        form = PostForm(instance=post)

    return render(request, "myapp/post_form.html", {"form": form})

用 Class-Based Views 進一步簡化

上面「新增/修改」的樣板程式碼其實高度重複,Django 內建的 CreateViewUpdateView 可以把這套流程再濃縮成幾行類別屬性,詳見 Class-Based Views

下一步

表單處理熟悉之後,可以進一步用 Class-Based Views 大幅減少 CRUD(新增、讀取、修改、刪除)介面的重複程式碼。