【Django 实验四】Form 与 ModelForm 表单实验
·
作业四:Form 与 ModelForm 表单实验
作者: 刘静怡 | 学号: F23016208 | 日期: 2026年4月
一、实验目的
- 掌握 Django 中 Form 和 ModelForm 的基本用法。
- 理解表单的数据验证机制(字段级验证和全局验证)。
- 学会使用表单的错误提示和前端渲染。
- 区分 Form(通用表单)和 ModelForm(数据库模型表单)的适用场景。
二、实验内容
本次作业基于作业一的 Django 基础,创建了一个包含多种表单类型的 Web 应用。项目包含三个表单:
| 表单名称 | 表单类型 | 说明 |
|---|---|---|
| 联系反馈表单 | Form | 演示通用表单的字段验证 |
| 个人信息登记 | ModelForm | 演示 ModelForm 直接操作数据库 |
| 调查问卷表单 | Form | 演示多种字段类型 |
三、核心代码解析
3.1 Form 实现:联系反馈表单
contact/forms.py 中定义了 ContactForm:
class ContactForm(forms.Form):
name = forms.CharField(min_length=2, max_length=50, label="姓名", ...)
phone = forms.CharField(min_length=11, max_length=11, label="手机号", ...)
email = forms.EmailField(label="邮箱", ...)
subject = forms.ChoiceField(label="反馈主题", choices=[...], ...)
message = forms.CharField(min_length=10, max_length=1000, label="留言内容", ...)
关键点:
CharField:字符字段,支持min_length和max_length。EmailField:自动验证邮箱格式。ChoiceField:下拉选择框,需要传入choices元组列表。widget参数:指定 HTML 渲染部件,如TextInput、Textarea、Select。error_messages参数:自定义错误提示文本。
字段级自定义验证
def clean_phone(self):
phone = self.cleaned_data.get("phone")
if phone and not phone.startswith("1"):
raise forms.ValidationError("手机号必须以1开头!")
return phone
- 方法名必须为
clean_<字段名>。 - 返回清洗后的数据。
- 抛出
ValidationError表示验证失败。
全局验证
def clean(self):
cleaned_data = super().clean()
# 可访问所有字段的 cleaned_data
return cleaned_data
clean()方法可以访问所有字段,进行跨字段验证。
3.2 视图函数:GET/POST 分支处理
contact/views.py 中的 contact_view:
@require_http_methods(["GET", "POST"])
def contact_view(request):
if request.method == "GET":
form = ContactForm() # 创建空白表单
return render(request, "contact/contact_form.html", {"form": form})
else:
form = ContactForm(request.POST) # 用POST数据实例化表单
if form.is_valid(): # 验证所有字段
name = form.cleaned_data.get("name") # 获取清洗后的数据
return HttpResponse(f"...")
else:
return render(request, "contact/contact_form.html", {"form": form})
流程图:
GET请求
└─> 创建空白表单 ContactForm()
└─> 渲染模板,显示空表单
POST请求
└─> 用 request.POST 实例化 ContactForm(request.POST)
└─> form.is_valid() ?
├─ True:获取 cleaned_data,返回成功页面
└─ False:返回表单(带错误信息)重新渲染
3.3 ModelForm 实现:个人信息登记
class PersonInfoForm(forms.ModelForm):
confirm_email = forms.EmailField(label="确认邮箱", ...) # 额外字段
class Meta:
model = PersonInfo # 指定关联的模型
fields = ["name", "gender", "birth_date", "hometown", "email", "phone", "bio"]
labels = {...} # 字段中文标签
widgets = {...} # HTML部件
error_messages = {...} # 错误信息
ModelForm 与 Form 的核心区别:
| 对比项 | Form | ModelForm |
|---|---|---|
| 数据来源 | 手动定义字段 | 从模型自动推断字段 |
| 保存数据库 | 需要手动 form.cleaned_data 后 Model.objects.create() |
直接 form.save() |
| 适用场景 | 无数据库关联的表单 | 需要增删改查的表单 |
Meta 类 |
不需要 | 必须指定 model 和 fields |
3.4 模板渲染
使用 Django 模板引擎遍历所有字段:
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
{% endif %}
{% endfor %}
<button type="submit">提交</button>
</form>
{{ field }}:自动渲染对应的 HTML 输入部件。{{ field.id_for_label }}:获取<label>的for属性值。{{ field.label }}:获取字段的中文标签。{{ field.errors }}:渲染验证错误信息。
四、实验结果
4.1 三个表单页面
访问 http://127.0.0.1:8000/ 显示首页,提供三个表单入口:
- 联系反馈 (
/contact/):Form 实现,含5个字段 + 自定义验证 - 个人信息登记 (
/person/):ModelForm 实现,数据直接写入数据库 - 问卷调查 (
/survey/):Form 实现,含复选框组和数字字段
4.2 表单验证效果
| 场景 | 预期结果 | 实际结果 |
|---|---|---|
| 手机号少于11位 | 显示"手机号必须是11位!" | 正常 |
| 邮箱格式错误 | 显示"请输入有效的邮箱地址!" | 正常 |
| 留言内容含"垃圾" | 显示"留言内容包含敏感词:垃圾" | 正常 |
| 两次邮箱不一致(ModelForm) | 显示"两次输入的邮箱不一致!" | 正常 |
| 所有字段合法 | 显示提交成功结果 | 正常 |
五、关键知识点总结
5.1 表单字段类型
| 字段类 | 对应HTML | 说明 |
|---|---|---|
CharField |
<input type="text"> |
单行文本 |
IntegerField |
<input type="number"> |
整数 |
EmailField |
<input type="email"> |
邮箱(自动验证) |
ChoiceField |
<select> |
单选下拉框 |
MultipleChoiceField |
多个<input type="checkbox"> |
多选复选框 |
DateField |
<input type="date"> |
日期 |
BooleanField |
<input type="checkbox"> |
布尔值 |
5.2 验证钩子
clean_<fieldname>():单字段验证,抛出ValidationError表示失败。clean():多字段联合验证。is_valid():触发所有验证,返回True/False。cleaned_data:验证通过后,存储所有清洗后数据的字典。
5.3 Widget 部件
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "..."})
widget=forms.Textarea(attrs={"class": "form-control", "rows": 5})
widget=forms.Select(attrs={"class": "form-select"})
widget=forms.CheckboxSelectMultiple()
widget=forms.RadioSelect()
5.4 Form vs ModelForm 选择
- 选择 Form:表单数据不需要保存到数据库,或者字段与模型不对应。
- 选择 ModelForm:表单数据需要创建/更新数据库记录。
六、实验环境
- Python:3.11+
- Django:5.2
- 数据库:MySQL 8.0(phpstudy_pro)
- 前端框架:Bootstrap 5.3.0
启动步骤
# 1. 创建虚拟环境
python -m venv venv
.\venv\Scripts\activate
# 2. 安装依赖
pip install -r requirements.txt
# 3. 创建数据库(在MySQL中执行)
CREATE DATABASE exp4_form CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 4. 执行迁移
python manage.py makemigrations
python manage.py migrate
# 5. 创建管理员
python create_superuser.py
# 6. 启动服务器
python manage.py runserver
访问地址:
- 首页:
http://127.0.0.1:8000/ - 管理后台:
http://127.0.0.1:8000/admin/ - 首页查看

页面内容查看


后台查看
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)