Django 中的 forms.ModelForm
—— 它是 Django 表單系統和 ORM 的一個“橋梁”,能幫助你快速基于 數據庫模型(Model) 自動生成表單,極大減少重復代碼。
1. 什么是 ModelForm
- 普通 Form (
forms.Form
):完全手寫字段,和數據庫模型沒有直接關系。 - ModelForm (
forms.ModelForm
):根據 Django ORM 的 Model 自動生成表單字段,避免重復定義字段。
換句話說,ModelForm
= Form + Model 映射。
你只需要指定關聯的模型 model
,Django 會自動:
- 根據模型字段生成對應的表單字段;
- 自動處理數據校驗(包括數據庫字段約束,如
max_length
、unique
); - 提供
save()
方法,可以直接保存到數據庫。
2. 基本用法
模型定義
# models.py
from django.db import modelsclass Book(models.Model):title = models.CharField(max_length=100)author = models.CharField(max_length=50)published_date = models.DateField()price = models.DecimalField(max_digits=6, decimal_places=2)def __str__(self):return self.title
ModelForm 定義
# forms.py
from django import forms
from .models import Bookclass BookForm(forms.ModelForm):class Meta:model = Bookfields = '__all__' # 或 ['title', 'author']
視圖中使用
# views.py
from django.shortcuts import render, redirect
from .forms import BookFormdef create_book(request):if request.method == "POST":form = BookForm(request.POST)if form.is_valid(): # 自動根據模型字段校驗form.save() # 直接保存到數據庫return redirect('book_list')else:form = BookForm()return render(request, 'book_form.html', {'form': form})
模板中渲染
<form method="post">{% csrf_token %}{{ form.as_p }} <!-- 自動渲染為 <p> 包裹的表單控件 --><button type="submit">保存</button>
</form>
3. ModelForm
的關鍵點
3.1 Meta
類配置
ModelForm
必須包含一個 Meta
內部類,用來定義表單和模型的關系。
常用屬性:
- model:指定關聯的模型
- fields:指定要包含的字段(推薦用列表,不要總用
__all__
) - exclude:排除某些字段
- widgets:指定表單控件樣式(比如 HTML input)
- labels:自定義字段的標簽
- help_texts:字段提示文字
- error_messages:自定義錯誤提示
示例:
class BookForm(forms.ModelForm):class Meta:model = Bookfields = ['title', 'author', 'price'] # 只要部分字段labels = {'title': '書名','author': '作者',}help_texts = {'price': '請輸入價格(單位:元)',}error_messages = {'title': {'max_length': '書名太長了!',},}widgets = {'published_date': forms.SelectDateWidget(years=range(2000, 2030)),}
4. 表單數據的保存
4.1 新增
form = BookForm(request.POST)
if form.is_valid():book = form.save() # 直接保存到數據庫
4.2 不立即保存
有時候需要在保存前修改對象,可以用 commit=False
:
book = form.save(commit=False)
book.price = book.price * 0.9 # 打折
book.save()
4.3 更新已有對象
book = Book.objects.get(pk=1)
form = BookForm(request.POST, instance=book) # 綁定已有對象
if form.is_valid():form.save() # 會執行 update 而不是 insert
5. 表單校驗
5.1 自動校驗
- 來自模型字段的限制(
max_length
、unique
、blank
等) - 自動映射到表單校驗規則
5.2 自定義校驗
可以通過重寫 clean_<field>()
或 clean()
:
方法名中的<field>
必須和表單字段名一致;
class BookForm(forms.ModelForm):class Meta:model = Bookfields = '__all__'def clean_price(self):price = self.cleaned_data['price']if price <= 0:raise forms.ValidationError("價格必須大于0!")return pricedef clean(self):cleaned_data = super().clean()title = cleaned_data.get('title')author = cleaned_data.get('author')if title and author and "Django" not in title and author == "某某":raise forms.ValidationError("某某只能寫 Django 相關的書!")return cleaned_data
調用順序:
- 表單調用了
is_valid()
,從而觸發了full_clean() → clean_fields() → clean_<field>()
。
6. ModelForm
的高級用法
6.1 內聯表單(Inline Formset)
Django 提供了 inlineformset_factory
,可以在一個表單中編輯主表和子表。
常用于:一個 Author
對應多個 Book
的場景。
from django.forms import inlineformset_factory
BookFormSet = inlineformset_factory(Author, Book, fields=['title', 'price'])
6.2 ModelForm
與 modelform_factory
如果表單邏輯簡單,可以用 modelform_factory
快速生成:
from django.forms import modelform_factory
BookForm = modelform_factory(Book, fields=['title', 'author'])
7. Form
vs ModelForm
對比
特點 | Form | ModelForm |
---|---|---|
字段定義 | 手動寫每個字段 | 自動從 Model 生成 |
數據校驗 | 需手動寫 | 自動結合 Model 的字段規則 |
保存到數據庫 | 需手動處理模型對象保存 | 直接用 save() |
使用場景 | 與數據庫無關的表單 | 與模型強關聯的 CRUD 表單 |
8. 使用場景總結
? 適合:
- 表單與數據庫模型字段高度一致的場景(如后臺管理系統、標準 CRUD 表單)
- 希望快速生成表單,減少重復代碼
?? 不適合:
- 表單和模型差別很大(例如前端提交的數據字段和數據庫存儲結構完全不一樣)
- 需要復雜的自定義邏輯時,建議繼承
forms.Form