Django ModelForm 实战:从基础用法到数据验证与编辑

Ivy
Ivy
发布时间:2026-10-13| 7人浏览过
原创

本文详解 Django 中 ModelForm 组件的核心用法。通过定义继承自 ModelForm 的类及 Meta 内部类,可自动将数据库模型映射为前端表单。内容涵盖字段显示、自定义 Widget 样式、错误信息处理,以及利用 instance 参数实现数据的自动回显与更新保存,旨在提供比手动编写表单更优雅高效的后端解决方案。

这是一个功能强大的组件,从名称即可推断其作用:将 Model(模型)与 Form(表单)结合。没错,正如你预期的那样,它旨在简化这两者的交互。

首先通过一个简单示例展示其基本用法:

假设数据库中有一张学生表,包含姓名、年龄、爱好、邮箱、电话、住址、注册时间等多个字段。现在需要开发一个创建学生的页面,后端应如何处理?

常规做法是前端逐一列出这些字段供用户填写,后端逐一接收输入,创建新的学生对象并保存。

然而,核心难点在于合法性验证。我们需要在前端判断用户输入是否符合规范,例如姓名长度限制、电话号码位数、邮箱格式等。

虽然可以手动编写各种限制和判断逻辑,但这显然繁琐且低效。

这里提供一种更优雅(在 Python 开发中应养成使用“优雅”一词的习惯)的方法:ModelForm。

先演示基本用法,随后再添加验证条件:

首先导入 ModelForm 模块。

from django.forms import ModelForm

在视图函数中定义一个类(例如 StudentList),该类需继承 ModelForm。在此类内部定义一个名为 Meta 的内部类(注意首字母大写,这是固定写法)。

在 Meta 内部类中,可以配置以下属性(部分示例):

class StudentList(ModelForm):
  class Meta:
    model = models.Student #对应的Model中的类
    fields = "__all__"   #字段,如果是__all__,就是表示列出所有的字段
    exclude = None     #排除的字段
    labels = None      #提示信息
    help_texts = None    #帮助提示信息
    widgets = None     #自定义插件
    error_messages = None  #自定义错误信息
#error_messages用法:
    error_messages = {
      'name':{'required':"用户名不能为空",},
      'age':{'required':"年龄不能为空",},
    }
#widgets用法,比如把输入用户名的input框给为Textarea
#首先得导入模块
    from django.forms import widgets as wid #因为重名,所以起个别名
    widgets = {
      "name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性
    }
#labels,自定义在前端显示的名字
    labels= {
      "name":"用户名"
    }

接着,在 URL 对应的视图函数中实例化该类,并将该对象传递给前端模板。

def student(request):

  if request.method == 'GET':
    student_list = StudentList()
    return render(request,'student.html',{'student_list':student_list})

前端只需使用 {{ student_list.as_p }} 即可渲染所有字段。虽然可以使用 as_p 直接显示,但也可以通过 for 循环遍历 student_list,获取各个 input 框。为了获得更好的页面效果,我们通常不使用 as_p,而是手动构建这些 input 框。

首先对 student_list 进行 for 循环,获取 student 对象,直接在前端打印该对象即可得到 input 框。通过 student.label 可以获取数据库中每个字段的 verbose_name(如果未设置,则默认显示字段名)。

此外,还可以通过 student.errors.0 获取具体的错误信息。

利用上述信息,我们可以结合 Bootstrap 框架自定义所需的页面样式。

例如:

<body>
  <div class="container" >
    <h1>student</h1>
    <form method="POST" novalidate>
      {% csrf_token %}
{#      {{ student_list.as_p }}#}
      {% for student in student_list %}
        <div class="form-group col-md-6">
         {# 拿到数据字段的verbose_name,没有就默认显示字段名 #}
          <label class="col-md-3 control-label">{{ student.label }}</label>
          <div class="col-md-9" style="position: relative;">{{ student }}</div>
        </div>
      {% endfor %}
      <div class="col-md-2 col-md-offset-10">
        <input type="submit" value="提交" class="btn-primary">
      </div>
    </form>
  </div>
</body>

目前还缺少 input 框的 form-control 样式,可以考虑在后台的 widget 配置中添加。

具体配置如下:

from django.forms import widgets as wid #因为重名,所以起个别名
    widgets = {
      "name":wid.TextInput(attrs={'class':'form-control'}),
      "age":wid.NumberInput(attrs={'class':'form-control'}),
      "email":wid.EmailInput(attrs={'class':'form-control'})
    }

当然,也可以在 JavaScript 中查找所有 input 框并动态添加该样式,这也是可行的替代方案。

在保存数据时,无需逐个提取数据,直接调用 save() 方法即可。

def student(request):

  if request.method == 'GET':
    student_list = StudentList()
    return render(request,'student.html',{'student_list':student_list})
  else:
    student_list = StudentList(request.POST)
    if student_list.is_valid():
      student_list.save()
    return redirect(request,'student_list.html',{'student_list':student_list})

接下来介绍编辑数据的场景:

如果不使用 ModelForm,编辑时需手动显示原有数据并逐个取值。而使用 ModelForm 时,只需在实例化时添加 instance=obj(obj 为待修改的数据库记录对象)即可实现同样的回显效果。

保存数据时需特别注意:必须传入该对象(instance=obj),否则系统无法确定更新哪一条数据。

相关代码示例如下:

from django.shortcuts import render,HttpResponse,redirect
from django.forms import ModelForm
# Create your views here.
from app01 import models
def test(request):
  # model_form = models.Student
  model_form = models.Student.objects.all()
  return render(request,'test.html',{'model_form':model_form})

class StudentList(ModelForm):
  class Meta:
    model = models.Student #对应的Model中的类
    fields = "__all__"   #字段,如果是__all__,就是表示列出所有的字段
    exclude = None     #排除的字段
    labels = None      #提示信息
    help_texts = None    #帮助提示信息
    widgets = None     #自定义插件
    error_messages = None  #自定义错误信息
#error_messages用法:
    error_messages = {
      'name':{'required':"用户名不能为空",},
      'age':{'required':"年龄不能为空",},
    }
#widgets用法,比如把输入用户名的input框给为Textarea
#首先得导入模块
    from django.forms import widgets as wid #因为重名,所以起个别名
    widgets = {
      "name":wid.Textarea
    }
#labels,自定义在前端显示的名字
    labels= {
      "name":"用户名"
    }
def student(request):
  if request.method == 'GET':
    student_list = StudentList()
    return render(request,'student.html',{'student_list':student_list})
  else:
    student_list = StudentList(request.POST)
    if student_list.is_valid():
      student_list.save()
    return render(request,'student.html',{'student_list':student_list})
def student_edit(request,pk):
  obj = models.Student.objects.filter(pk=pk).first()
  if not obj:
    return redirect('test')
  if request.method == "GET":
    student_list = StudentList(instance=obj)
    return render(request,'student_edit.html',{'student_list':student_list})
  else:
    student_list = StudentList(request.POST,instance=obj)
    if student_list.is_valid():
      student_list.save()
    return render(request,'student_edit.html',{'student_list':student_list})

总结

以上为 Django 中 ModelForm 组件的详细用法说明,希望对你有所帮助。感兴趣的朋友可继续查阅本站其他 Python 相关教程,如有疏漏欢迎留言指正。感谢支持!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。