Django ModelForm 筆記

Django ModelForm 筆記

✅ ModelForm 的目的與用途

Django 的 ModelForm 提供了一個方便的方法,讓我們可以快速根據模型創建表單。它自動從模型推導表單欄位,並進行表單驗證與資料處理。使用 ModelForm 可以減少手動創建表單類別的工作,提高開發效率。

📝 ModelForm 的常用設定

1. fields / exclude

  • model: 指定是哪個 model
  • fields: 指定哪些欄位會被包含在表單中。
  • exclude: 排除某些欄位,不會顯示在表單中。

forms.py

class InterviewForm(ModelForm):
    class Meta:
        model = Interview
        fields = ['company_name', 'position', 'interview_date', 'review', 'rating', 'result']
        # exclude = ['is_admin']  # 不想包含的欄位
        # fields = "__all__" 接受所有欄位,不建議這麼做

2. labels

可以自定義欄位顯示名稱:

labels = {
    'company_name': '公司名稱',
    'position': '職位',
    'interview_date': '面試日期',
    'review': '心得',
    'rating': '評分',
    'result': '面試結果'
}

3. widgets

控制欄位的輸入類型,特別針對日期或其他自定義輸入:

from django.forms import DateInput

widgets = {
    'interview_date': DateInput(attrs={'type': 'date'})
}

💡 在 Views 中使用

ModelForm 可以幫助我們簡化新增與更新資料的邏輯:

新增資料

def index(req):
    if req.POST:
        form = InterviewForm(req.POST)  # 沒有傳入 instance,代表要新增資料
        interview = form.save()  # 存入資料庫並回傳 instance
        return redirect("interviews:show", id=interview.id)
    else:
        interviews = Interview.objects.order_by("-id")
        return render(req, "interviews/index.html", {"interviews": interviews})

編輯資料

def show(req, id):
    interview = get_object_or_404(Interview, pk=id)

    if req.POST:
        form = InterviewForm(req.POST, instance=interview)  # 有傳入 instance,代表要更新資料
        form.save()
        return redirect("interviews:show", interview.id)
    else:
        comments = interview.comment_set.all()
        return render(req, "interviews/show.html", {"interview": interview, "comments": comments})

預填表單(編輯頁面)

def edit(req, id):
    interview = get_object_or_404(Interview, pk=id)
    form = InterviewForm(instance=interview)  # 預填現有資料
    return render(req, "interviews/edit.html", {"interview": interview, "form": form})

🔄 創建 vs 更新資料

在使用 ModelForm 時,可透過 instance 參數來決定是要 創建 還是 更新 資料:

# 創建新的資料(不提供 instance)
form = InterviewForm(request.POST)
if form.is_valid():
    form.save()  # 會建立一筆新的 Interview 紀錄

# 更新既有資料(提供 instance)
form = InterviewForm(request.POST, instance=interview)
if form.is_valid():
    form.save()  # 會更新傳入的 interview 物件
  • 不提供 instanceform.save() 會執行 INSERT,新增一筆資料。
  • 提供 instanceform.save() 會執行 UPDATE,更新該物件的欄位。

🖥️ 在 Templates 中使用

<form method="post">
  {% csrf_token %}
  {{ form.as_p }}  <!-- 將表單欄位渲染為段落 -->
  <button type="submit">提交</button>
</form>
  • {{ form.as_p }}:快捷渲染
  • csrf_token:防止 CSRF 攻擊

🎯 ModelForm 的優勢

  • 自動生成表單欄位:無需手動一一定義。
  • 自動資料驗證:根據模型欄位類型自動檢查輸入。
  • 簡化新增與更新資料的邏輯:直接使用 form.save() 完成。
  • 程式碼更簡潔、可維護性更高