Django Form 与 ModelForm 实战:从留言板 Demo 到图书登记系统

张开发
2026/4/21 2:16:08 15 分钟阅读

分享文章

Django Form 与 ModelForm 实战:从留言板 Demo 到图书登记系统
作业背景第四次作业要求使用 Form 或 ModelForm 完善 quickstart 项目功能。本文基于课程留言板 Demo扩展实现一个图书登记系统使用 ModelForm 完成数据验证与数据库存储。一、前置说明课程 Demo 中实现了基于forms.Form的留言板功能包含标题、内容、邮箱三个字段通过form.cleaned_data手动提取数据。本次作业在此基础上改用forms.ModelForm实现图书登记功能体会两者的核心差异。ModelForm 的核心优势在于字段自动生成、验证规则与模型同步、支持form.save()直接持久化到数据库。二、项目结构在原有项目基础上新增library应用最终目录结构如下mysite/ ├── library/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── forms.py # 新增ModelForm 定义 │ ├── models.py # 新增Book 模型 │ ├── urls.py # 新增应用路由 │ └── views.py # 新增图书登记视图 ├── mysite/ │ ├── __init__.py │ ├── settings.py # 修改注册应用、配置模板 │ ├── urls.py # 修改包含 library 路由 │ └── wsgi.py ├── templates/ │ └── book_form.html # 新增模板文件 ├── manage.py └── db.sqlite3三、详细操作步骤步骤 1创建应用在项目根目录下执行cd mysite python manage.py startapp library步骤 2注册应用并配置模板目录修改mysite/settings.py在INSTALLED_APPS列表末尾追加libraryINSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, library, ]确认TEMPLATES配置中DIRS包含全局模板路径TEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [BASE_DIR / templates], APP_DIRS: True, OPTIONS: { context_processors: [ django.template.context_processors.debug, django.template.context_processors.request, django.contrib.auth.context_processors.auth, django.contrib.messages.context_processors.messages, ], }, }, ]步骤 3定义数据模型修改library/models.py定义Book模型from django.db import models class Book(models.Model): title models.CharField(max_length100, verbose_name书名) author models.CharField(max_length50, verbose_name作者) publish_date models.DateField(verbose_name出版日期) price models.DecimalField(max_digits10, decimal_places2, verbose_name价格) introduction models.TextField(blankTrue, verbose_name简介) contact_email models.EmailField(verbose_name联系邮箱) created_at models.DateTimeField(auto_now_addTrue, verbose_name登记时间) class Meta: verbose_name 图书 verbose_name_plural 图书 ordering [-created_at] def __str__(self): return self.title执行数据库迁移命令python manage.py makemigrations python manage.py migrate步骤 4创建 ModelForm在library目录下新建forms.pyfrom django import forms from .models import Book class BookForm(forms.ModelForm): class Meta: model Book fields [title, author, publish_date, price, introduction, contact_email] labels { title: 图书名称, author: 作者姓名, publish_date: 出版日期, price: 定价 (元), introduction: 内容简介, contact_email: 联系邮箱, } error_messages { title: { required: 书名不能为空, max_length: 书名最长不能超过100个字符, }, author: { required: 请填写作者姓名, }, price: { required: 请输入图书价格, invalid: 请输入有效的数字, }, contact_email: { required: 请填写联系邮箱, invalid: 邮箱格式不正确, } } widgets { publish_date: forms.DateInput(attrs{type: date, class: form-control}), introduction: forms.Textarea(attrs{rows: 4, placeholder: 请输入图书简介..., class: form-control}), title: forms.TextInput(attrs{class: form-control, placeholder: 请输入书名}), author: forms.TextInput(attrs{class: form-control, placeholder: 请输入作者}), price: forms.NumberInput(attrs{class: form-control, step: 0.01}), contact_email: forms.EmailInput(attrs{class: form-control, placeholder: exampleemail.com}), } def clean_price(self): price self.cleaned_data.get(price) if price is not None and price 0: raise forms.ValidationError(价格不能为负数) return price步骤 5编写视图修改library/views.pyfrom django.shortcuts import render from django.http import HttpResponse from django.views.decorators.http import require_http_methods from .forms import BookForm require_http_methods([GET, POST]) def book_register(request): if request.method GET: form BookForm() return render(request, book_form.html, context{form: form}) else: form BookForm(request.POST) if form.is_valid(): book form.save() return HttpResponse( f图书登记成功br f书名《{book.title}》br f作者{book.author}br f价格¥{book.price}br f邮箱{book.contact_email} ) else: return render(request, book_form.html, context{form: form})步骤 6配置路由修改项目级路由mysite/urls.pyfrom django.contrib import admin from django.urls import path, include urlpatterns [ path(admin/, admin.site.urls), path(book/, include(library.urls)), ]在library目录下新建urls.pyfrom django.urls import path from . import views urlpatterns [ path(, views.book_register, namebook_register), ]步骤 7编写模板在项目根目录与manage.py同级创建templates文件夹并在其中新建book_form.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 title图书登记/title style body { font-family: Microsoft YaHei, Arial, sans-serif; max-width: 500px; margin: 50px auto; background: #f5f5f5; } .container { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h2 { text-align: center; color: #333; margin-bottom: 25px; } .form-group { margin-bottom: 18px; } label { display: block; margin-bottom: 6px; font-weight: bold; color: #555; } input, textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } input:focus, textarea:focus { border-color: #4CAF50; outline: none; } .errorlist { color: #d32f2f; margin: 5px 0 0 0; padding: 0; list-style: none; font-size: 13px; } button { width: 100%; padding: 12px; background: #4CAF50; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; margin-top: 10px; } button:hover { background: #45a049; } /style /head body div classcontainer h2图书登记系统/h2 form methodpost action {% csrf_token %} {% for field in form %} div classform-group {{ field.label_tag }} {{ field }} {% if field.errors %} ul classerrorlist {% for error in field.errors %} li{{ error }}/li {% endfor %} /ul {% endif %} /div {% endfor %} button typesubmit提交登记/button /form /div /body /html步骤 8运行项目执行开发服务器python manage.py runserver访问http://127.0.0.1:8000/book/即可看到图书登记页面。四、核心知识点对比Form 与 ModelForm 的本质区别forms.Form需要开发者手动声明每一个字段手动编写视图中的数据保存逻辑适合不存入数据库的场景例如搜索框、联系表单。forms.ModelForm通过Meta类中的model和fields自动映射模型字段验证规则继承自模型定义通过form.save()一行代码即可完成数据库持久化适合所有需要与数据库交互的增删改场景。三种验证层级第一层级是字段参数验证通过min_length、max_length、required等参数控制在字段定义时完成。第二层级是单字段自定义验证通过clean_字段名()方法实现例如本文中对价格负数的检查。第三层级是整表联合验证通过重写clean()方法实现适用于多个字段之间存在逻辑关联的场景例如确认密码是否一致、结束日期不能早于开始日期等。五、复习建议第一将本文的BookForm从ModelForm改写为Form版本手动定义所有字段并编写视图中的保存逻辑体会两者的代码量差异。第二在模板中尝试手动渲染单个字段而非循环渲染掌握form.title、form.title.errors、form.title.label_tag的用法。第三新增一个isbn字段要求必须为 13 位纯数字通过clean_isbn()方法实现正则验证。第四进入 Django Admin 后台确认数据是否成功写入数据库理解form.save()背后的 ORM 操作。六、总结本次作业基于课程留言板 Demo通过 ModelForm 实现了图书登记功能覆盖了模型定义、表单验证、模板渲染、数据持久化的完整流程。ModelForm 的最大价值在于减少重复代码使表单验证与模型约束保持同步是 Django 实际开发中的首选方案。后续可以继续在此项目基础上扩展添加图书列表页、编辑功能、删除功能逐步完善为一个完整的 CRUD 应用。

更多文章