作业四:Form 与 ModelForm 表单实验

作者: 刘静怡 | 学号: F23016208 | 日期: 2026年4月


一、实验目的

  1. 掌握 Django 中 FormModelForm 的基本用法。
  2. 理解表单的数据验证机制(字段级验证和全局验证)。
  3. 学会使用表单的错误提示前端渲染
  4. 区分 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_lengthmax_length
  • EmailField:自动验证邮箱格式。
  • ChoiceField:下拉选择框,需要传入 choices 元组列表。
  • widget 参数:指定 HTML 渲染部件,如 TextInputTextareaSelect
  • 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_dataModel.objects.create() 直接 form.save()
适用场景 无数据库关联的表单 需要增删改查的表单
Meta 不需要 必须指定 modelfields

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/
  • 首页查看
    在这里插入图片描述
    页面内容查看
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

后台查看
在这里插入图片描述

Logo

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

更多推荐