每天40分玩转Django:Django表单集
Django表单集
一、知识要点概览表
| 类别 | 知识点 | 掌握程度要求 |
|---|---|---|
| 基础概念 | FormSet、ModelFormSet | 深入理解 |
| 内联表单集 | InlineFormSet、BaseInlineFormSet | 熟练应用 |
| 表单集验证 | clean方法、验证规则 | 熟练应用 |
| 自定义配置 | extra、max_num、can_delete | 理解应用 |
| 动态管理 | JavaScript动态添加/删除表单 | 掌握使用 |
二、基础模型和表单设置
# models.py
from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)email = models.EmailField()bio = models.TextField()def __str__(self):return self.nameclass Book(models.Model):author = models.ForeignKey(Author, on_delete=models.CASCADE)title = models.CharField(max_length=200)isbn = models.CharField(max_length=13)publication_date = models.DateField()price = models.DecimalField(max_digits=10, decimal_places=2)def __str__(self):return self.title# forms.py
from django import forms
from .models import Author, Bookclass AuthorForm(forms.ModelForm):class Meta:model = Authorfields = ['name', 'email', 'bio']class BookForm(forms.ModelForm):class Meta:model = Bookfields = ['title', 'isbn', 'publication_date', 'price']
三、基本表单集实现
1. 创建表单集
# forms.py
from django.forms import modelformset_factory, formset_factory# 创建Book模型的表单集
BookFormSet = modelformset_factory(Book,form=BookForm,extra=2, # 额外空表单数量max_num=5, # 最大表单数量can_delete=True # 允许删除
)# 创建自定义表单集
class BaseBookFormSet(forms.BaseModelFormSet):def clean(self):super().clean()titles = []for form in self.forms:if form.cleaned_data:title = form.cleaned_data.get('title')if title in titles:raise forms.ValidationError("书籍标题不能重复")titles.append(title)# 使用自定义表单集基类
BookFormSet = modelformset_factory(Book,form=BookForm,formset=BaseBookFormSet,extra=2
)
2. 视图实现
# views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import BookFormSet, AuthorFormclass BookFormSetView(View):template_name = 'books/book_formset.html'def get(self, request):formset = BookFormSet(queryset=Book.objects.none())return render(request, self.template_name, {'formset': formset})def post(self, request):formset = BookFormSet(request.POST)if formset.is_valid():instances = formset.save()messages.success(request, f'成功保存{len(instances)}本书籍信息')return redirect('book_list')return render(request, self.template_name, {'formset': formset})def manage_books(request, author_id):author = get_object_or_404(Author, id=author_id)if request.method == 'POST':formset = BookFormSet(request.POST,queryset=Book.objects.filter(author=author))if formset.is_valid():books = formset.save(commit=False)for book in books:book.author = authorbook.save()# 处理删除的书籍for obj in formset.deleted_objects:obj.delete()return redirect('author_detail', pk=author.pk)else:formset = BookFormSet(queryset=Book.objects.filter(author=author))return render(request, 'books/manage_books.html', {'formset': formset,'author': author})
四、内联表单集实现
1. 创建内联表单集
# forms.py
from django.forms import inlineformset_factory# 创建Author-Book内联表单集
BookInlineFormSet = inlineformset_factory(Author, # 父模型Book, # 子模型form=BookForm,extra=2,max_num=5,can_delete=True
)# 自定义内联表单集
class BaseBookInlineFormSet(forms.BaseInlineFormSet):def clean(self):super().clean()total_price = 0for form in self.forms:if form.cleaned_data and not form.cleaned_data.get('DELETE', False):price = form.cleaned_data.get('price', 0)total_price += priceif total_price > 1000:raise forms.ValidationError("所有书籍总价不能超过1000")# 使用自定义内联表单集
BookInlineFormSet = inlineformset_factory(Author,Book,form=BookForm,formset=BaseBookInlineFormSet,extra=2
)
2. 视图实现
# views.py
from django.views.generic.edit import UpdateView
from .forms import BookInlineFormSetclass AuthorBooksUpdateView(UpdateView):model = Authorform_class = AuthorFormtemplate_name = 'books/author_books_form.html'def get_context_data(self, **kwargs):context = super().get_context_data(**kwargs)if self.request.POST:context['book_formset'] = BookInlineFormSet(self.request.POST,instance=self.object)else:context['book_formset'] = BookInlineFormSet(instance=self.object)return contextdef form_valid(self, form):context = self.get_context_data()book_formset = context['book_formset']if book_formset.is_valid():self.object = form.save()book_formset.instance = self.objectbook_formset.save()return redirect('author_detail', pk=self.object.pk)return self.render_to_response(self.get_context_data(form=form))
五、表单集模板实现
<!-- templates/books/author_books_form.html -->
{% extends 'base.html' %}
{% load static %}{% block content %}
<div class="container"><h1>编辑作者及其书籍</h1><form method="post">{% csrf_token %}<div class="author-form"><h2>作者信息</h2>{{ form.as_p }}</div><div class="books-formset"><h2>书籍信息</h2>{{ book_formset.management_form }}<div id="book-forms">{% for book_form in book_formset %}<div class="book-form">{{ book_form.non_field_errors }}<div class="form-row"><div class="form-group">{{ book_form.title.label_tag }}{{ book_form.title }}{{ book_form.title.errors }}</div><div class="form-group">{{ book_form.isbn.label_tag }}{{ book_form.isbn }}{{ book_form.isbn.errors }}</div><div class="form-group">{{ book_form.price.label_tag }}{{ book_form.price }}{{ book_form.price.errors }}</div>{% if book_form.instance.pk %}{{ book_form.DELETE }}{% endif %}</div></div>{% endfor %}</div><button type="button" id="add-book" class="btn btn-secondary">添加书籍</button></div><button type="submit" class="btn btn-primary mt-3">保存</button></form>
</div>{% block extra_js %}
<script>
$(document).ready(function() {// 获取表单总数const totalForms = $('#id_book_set-TOTAL_FORMS');// 添加新书籍表单$('#add-book').click(function() {const formCount = parseInt(totalForms.val());const newForm = $('#book-forms .book-form:first').clone(true);// 更新表单索引newForm.find(':input').each(function() {const name = $(this).attr('name').replace('-0-', '-' + formCount + '-');const id = 'id_' + name;$(this).attr({'name': name, 'id': id}).val('');});// 更新标签的for属性newForm.find('label').each(function() {const newFor = $(this).attr('for').replace('-0-', '-' + formCount + '-');$(this).attr('for', newFor);});// 添加新表单到DOM$('#book-forms').append(newForm);totalForms.val(formCount + 1);});
});
</script>
{% endblock %}
{% endblock %}
六、表单集处理流程图

七、高级用法示例
1. 工厂函数自定义
def get_book_formset(extra=1, max_num=None):return modelformset_factory(Book,form=BookForm,extra=extra,max_num=max_num,validate_max=True,can_delete=True,widgets={'title': forms.TextInput(attrs={'class': 'form-control'}),'isbn': forms.TextInput(attrs={'class': 'form-control'}),'price': forms.NumberInput(attrs={'class': 'form-control'})})# 在视图中使用
def manage_books_dynamic(request):BookFormSet = get_book_formset(extra=2,max_num=10)if request.method == 'POST':formset = BookFormSet(request.POST)if formset.is_valid():formset.save()return redirect('book_list')else:formset = BookFormSet()return render(request, 'books/manage_books.html', {'formset': formset})
2. 条件验证
class BaseBookFormSet(forms.BaseModelFormSet):def clean(self):super().clean()# 检查ISBN唯一性isbns = []for form in self.forms:if form.cleaned_data and not form.cleaned_data.get('DELETE', False):isbn = form.cleaned_data.get('isbn')if isbn in isbns:raise forms.ValidationError('ISBN必须唯一')isbns.append(isbn)# 检查总价格total_price = sum(form.cleaned_data.get('price', 0)for form in self.formsif form.cleaned_data and not form.cleaned_data.get('DELETE', False))if total_price > 1000:raise forms.ValidationError('所有书籍总价不能超过1000')
3. 动态表单处理
# views.py
from django.http import JsonResponseclass DynamicBookFormView(View):def post(self, request):if request.is_ajax():formset = BookFormSet(request.POST)if formset.is_valid():instances = formset.save()return JsonResponse({'status': 'success','message': f'成功保存{len(instances)}本书籍'})else:errors = []for form in formset:for field, error in form.errors.items():errors.append(f"{field}: {error}")return JsonResponse({'status': 'error','errors': errors})return JsonResponse({'status': 'error', 'message': '非法请求'})
这就是关于Django表单集的详细内容。通过学习这些内容,你将能够理解和使用Django的表单集系统,实现复杂的表单处理逻辑。如果有任何问题,欢迎随时提出!
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!
相关文章:
每天40分玩转Django:Django表单集
Django表单集 一、知识要点概览表 类别知识点掌握程度要求基础概念FormSet、ModelFormSet深入理解内联表单集InlineFormSet、BaseInlineFormSet熟练应用表单集验证clean方法、验证规则熟练应用自定义配置extra、max_num、can_delete理解应用动态管理JavaScript动态添加/删除表…...
查看vue的所有版本号和已安装的版本
1.使用npm查看Vue的所有版本: npm view vue versions2.查看项目中已安装的 Vue.js 版本 npm list vue...
钉钉h5微应用,鉴权提示dd.config错误说明,提示“jsapi ticket读取失败
这个提示大多是因为钉钉服务器没有成功读取到该企业的jsticket数据 1. 可能是你的企业corpid不对 登录钉钉管理后台 就可以找到对应企业的corpid 请严格使用这个corpid 。调用获取jsapi_ticket接口,使用的access_token对应的corpid和dd.config中传递的corpid不一致…...
【openGauss】正则表达式次数符号“{}“在ORACLE和openGauss中的差异
一、前言 正则作为一种常用的字符串处理方式,在各种开发语言,甚至数据库中,都有自带的正则函数。但是正则函数有很多标准,不同标准对正则表达式的解析方式不一样,本次在迁移一个ORACLE数据库到openGauss时发现了一个关…...
宏任务和微任务的区别
在 JavaScript 的异步编程模型中,宏任务(Macro Task)和微任务(Micro Task)是事件循环(Event Loop)机制中的两个重要概念。它们用于管理异步操作的执行顺序。 1. 宏任务 (Macro Task) 宏任务是较…...
数据库系统原理复习汇总
数据库系统原理复习汇总 一、数据库系统原理重点内容提纲 题型:主观题 1、简答题 第一章:数据库的基本概念:数据库、数据库管理系统、三级模式;两级映像、外码 第二章:什么是自然连接、等值连接; 第三…...
Linux day1204
五.安装lrzsz lrzsz 是用于在 Linux 系统中文件上传下载的软件。大家可能会存在疑问,我们用 MobaXterm 图形化界面就可以很方便的完成上传下载,为什么还要使用这个软件来 完成上传下载呢?实际上是这样的, Linux 的远程连接工具…...
如何在 Ubuntu 22.04 上安装并开始使用 RabbitMQ
简介 消息代理是中间应用程序,在不同服务之间提供可靠和稳定的通信方面发挥着关键作用。它们可以将传入的请求存储在队列中,并逐个提供给接收服务。通过以这种方式解耦服务,你可以使其更具可扩展性和性能。 RabbitMQ 是一种流行的开源消息代…...
【OpenGL ES】GLSL基础语法
1 前言 本文将介绍 GLSL 中数据类型、数组、结构体、宏、运算符、向量运算、矩阵运算、函数、流程控制、精度限定符、变量限定符(in、out、inout)、函数参数限定符等内容,另外提供了一个 include 工具,方便多文件管理 glsl 代码&a…...
如何使用交叉编译器调试C语言程序在安卓设备中运行
一、前言 随着移动设备的普及与技术的飞速发展,越来越多的开发者面临着在Android设备上运行和调试C语言等程序的需求。然而,在软件开发的世界里,不同硬件架构对程序运行的要求千差万别,这无疑增加了开发的复杂性。特别是在移动计…...
Java全栈项目 - 智能考勤管理系统
项目介绍 智能考勤管理系统是一个基于 Java 全栈技术开发的现代化企业考勤解决方案。该系统采用前后端分离架构,实现了员工考勤、请假管理、统计分析等核心功能,旨在帮助企业提高人力资源管理效率。 技术栈 后端技术 Spring Boot 2.6.xSpring Securi…...
Linux Shell : Process Substitution
注:本文为 “Process Substitution” 相关文章合辑。 英文引文机翻,未校。 Process Substitution. 进程替换允许使用文件名引用进程的输入或输出。它采取以下形式 <(list)or >(list)进程 list 异步运行,其输入或输出显示为文件名。…...
JOGL 从入门到精通:开启 Java 3D 图形编程之旅
一、引言 Java 作为一门广泛应用的编程语言,在图形编程领域也有着强大的工具和库。JOGL(Java OpenGL)便是其中之一,它为 Java 开发者提供了访问 OpenGL(Open Graphics Library)功能的接口,使得…...
汽车网络安全基线安全研究报告
一、引言 随着汽车行业朝着智能网联方向飞速发展,汽车网络安全已成为保障用户安全和行业健康发展的关键要素。本报告将深入探讨汽车网络安全相关内容,以及国际、国内重要的汽车网络安全标准基线和相应防护措施等内容。 二、汽车网络安全的重要性 &…...
Eclipse 修改项目栏字体大小
1、菜单栏选择window->preference,然后选择General->Appearance->Colors and Fonts,在搜索栏输入"tree",点击"Edit"修改字体。 2、修改字体,选择"四号字体",点击"确定&qu…...
【PCIe 总线及设备入门学习专栏 5.1 -- PCIe 引脚 PRSNT 与热插拔】
文章目录 OverviewPRSNT 与热插拔PRSNT 硬件设计 Overview Spec 定义的热插拔是把一个PCIe卡(设备)从一个正在运行的背板或者系统中插入/或者移除。这个过程需要不影响系统的其他功能。插入的新的设备可以正确工作。 显然,这里面需要考虑的问…...
【YOLO】YOLOv5原理
概述 YOLOv5的主要架构 Backbone(主干网络):负责提取输入图像的多层次特征 Neck(颈部网络):进行特征融合和多尺度特征处理,通常包含FPN(特征金字塔网络)和PAN࿰…...
uniapp中wx.getFuzzyLocation报错如何解决
一、用wx.getLocation接口审核不通过 用uniapp开发小程序时难免需要获取当前地理位置。 代码如下: uni.getLocation({type: wgs84,success: function (res) {console.log(当前位置的经度: res.longitude);console.log(当前位置的纬度: r…...
opencv图像直方图
【欢迎关注编码小哥,学习更多实用的编程方法和技巧】 1、基本直方图计算 // 灰度图直方图 cv::Mat calculateGrayscaleHistogram(const cv::Mat& image) {cv::Mat histogram;int histSize 256; // 灰度级别float range[] {0, 256};const float* histRange …...
OpenCV计算机视觉 03 椒盐噪声的添加与常见的平滑处理方式(均值、方框、高斯、中值)
上一篇文章:OpenCV计算机视觉 02 图片修改 图像运算 边缘填充 阈值处理 目录 添加椒盐噪声 图像平滑常见处理方式 均值滤波 (blur) 方框滤波 (boxFilter) 高斯滤波 (GaussianBlur) 中值滤波 (medianBlur) 添加椒盐噪声 def add_peppersalt_noise(image, n…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
