每天40分玩转Django:Django表单集

server/2024/12/25 12:59:16/

Django表单集

一、今日学习内容概述

学习模块重要程度主要内容
表单集基础⭐⭐⭐⭐⭐表单集定义、基本用法
内联表单集⭐⭐⭐⭐⭐内联表单、关联数据
表单集验证⭐⭐⭐⭐自定义验证、错误处理
动态表单集⭐⭐⭐⭐动态添加删除表单

二、基本模型定义

python"># models.py
from django.db import modelsclass Author(models.Model):name = models.CharField('姓名', max_length=100)email = models.EmailField('邮箱')bio = models.TextField('简介', blank=True)def __str__(self):return self.nameclass Book(models.Model):title = models.CharField('书名', max_length=200)author = models.ForeignKey(Author,on_delete=models.CASCADE,related_name='books')isbn = models.CharField('ISBN', max_length=13)published_date = models.DateField('出版日期')price = models.DecimalField('价格', max_digits=10, decimal_places=2)def __str__(self):return self.titleclass Chapter(models.Model):book = models.ForeignKey(Book,on_delete=models.CASCADE,related_name='chapters')title = models.CharField('章节标题', max_length=200)content = models.TextField('内容')order = models.PositiveIntegerField('排序')class Meta:ordering = ['order']def __str__(self):return self.title

三、表单集实现

3.1 基本表单集

python"># forms.py
from django import forms
from django.forms import formset_factory, modelformset_factory
from .models import Book, Chapterclass BookForm(forms.ModelForm):class Meta:model = Bookfields = ['title', 'isbn', 'published_date', 'price']widgets = {'published_date': forms.DateInput(attrs={'type': 'date'})}# 创建基本表单集
BookFormSet = modelformset_factory(Book,form=BookForm,extra=2,can_delete=True
)# 创建章节表单
class ChapterForm(forms.ModelForm):class Meta:model = Chapterfields = ['title', 'content', 'order']# 创建章节表单集
ChapterFormSet = modelformset_factory(Chapter,form=ChapterForm,extra=1,can_delete=True
)

3.2 内联表单集

python"># forms.py
from django.forms import inlineformset_factory# 创建内联表单集
BookChapterFormSet = inlineformset_factory(Book,Chapter,form=ChapterForm,extra=3,can_delete=True,min_num=1,validate_min=True
)class AuthorBooksForm(forms.ModelForm):class Meta:model = Authorfields = ['name', 'email', 'bio']AuthorBooksFormSet = inlineformset_factory(Author,Book,form=BookForm,extra=1,can_delete=True
)

四、视图实现

python"># views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from .forms import BookFormSet, ChapterFormSet, BookChapterFormSet
from .models import Book, Authordef manage_books(request):if request.method == 'POST':formset = BookFormSet(request.POST)if formset.is_valid():formset.save()messages.success(request, '书籍信息保存成功!')return redirect('book_list')else:formset = BookFormSet()return render(request, 'books/manage_books.html', {'formset': formset})def edit_book_chapters(request, book_id):book = get_object_or_404(Book, id=book_id)if request.method == 'POST':formset = BookChapterFormSet(request.POST, instance=book)if formset.is_valid():formset.save()messages.success(request, '章节信息保存成功!')return redirect('book_detail', book_id=book.id)else:formset = BookChapterFormSet(instance=book)return render(request, 'books/edit_chapters.html', {'book': book,'formset': formset})def author_books(request, author_id):author = get_object_or_404(Author, id=author_id)if request.method == 'POST':form = AuthorBooksForm(request.POST, instance=author)formset = AuthorBooksFormSet(request.POST, instance=author)if form.is_valid() and formset.is_valid():form.save()formset.save()messages.success(request, '作者和图书信息保存成功!')return redirect('author_detail', author_id=author.id)else:form = AuthorBooksForm(instance=author)formset = AuthorBooksFormSet(instance=author)return render(request, 'books/author_books.html', {'form': form,'formset': formset})

五、模板实现

<!-- templates/books/manage_books.html -->
{% extends "base.html" %}{% block content %}
<div class="container mt-4"><h2>管理图书</h2><form method="post">{% csrf_token %}{{ formset.management_form }}<div class="formset-container">{% for form in formset %}<div class="card mb-3 book-form"><div class="card-body">{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}<div class="row"><div class="col-md-6">{{ form.title.label_tag }}{{ form.title }}</div><div class="col-md-3">{{ form.isbn.label_tag }}{{ form.isbn }}</div><div class="col-md-3">{{ form.price.label_tag }}{{ form.price }}</div></div>{% if form.can_delete %}<div class="form-check mt-2">{{ form.DELETE }}<label class="form-check-label">删除此书</label></div>{% endif %}</div></div>{% endfor %}</div><button type="submit" class="btn btn-primary">保存</button></form>
</div>
{% endblock %}<!-- JavaScript for dynamic forms -->
<script>
document.addEventListener('DOMContentLoaded', function() {const formsetContainer = document.querySelector('.formset-container');const totalForms = document.querySelector('#id_form-TOTAL_FORMS');function updateFormIndex(element, index) {element.id = element.id.replace('-__prefix__-', `-${index}-`);element.name = element.name.replace('-__prefix__-', `-${index}-`);}// Add form dynamicallyfunction addForm() {const forms = formsetContainer.querySelectorAll('.book-form');const formNum = forms.length;const newForm = forms[0].cloneNode(true);// Clear form valuesnewForm.querySelectorAll('input').forEach(input => {input.value = '';updateFormIndex(input, formNum);});formsetContainer.appendChild(newForm);totalForms.value = formNum + 1;}
});
</script>

六、表单集流程图

在这里插入图片描述

七、验证与错误处理

python"># forms.py
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)# 使用自定义基类
BookFormSet = modelformset_factory(Book,form=BookForm,formset=BaseBookFormSet,extra=2,can_delete=True
)

八、实用工具函数

python"># utils.py
def copy_formset_instance(formset):"""复制表单集实例"""new_formset = formset.__class__(queryset=formset.queryset,initial=[form.initial for form in formset.forms],prefix=formset.prefix)return new_formsetdef get_changed_data(formset):"""获取表单集中已更改的数据"""changed_objects = []for form in formset.forms:if form.has_changed() and not form.cleaned_data.get('DELETE', False):changed_objects.append(form.instance)return changed_objects

九、常见问题和解决方案

  1. 表单集验证失败
python">def handle_formset_errors(formset):"""处理表单集错误"""errors = []for i, form in enumerate(formset):if form.errors:errors.append(f'表单 {i + 1}: {form.errors}')if formset.non_form_errors():errors.append(f'整体错误: {formset.non_form_errors()}')return errors
  1. 动态表单处理
// 动态添加和删除表单的JavaScript代码
function initDynamicFormset() {const addButton = document.getElementById('add-form');const formContainer = document.querySelector('.formset-container');const totalForms = document.getElementById('id_form-TOTAL_FORMS');addButton.addEventListener('click', function() {const forms = formContainer.getElementsByClassName('dynamic-form');const formCount = forms.length;const newForm = forms[0].cloneNode(true);// 更新表单索引newForm.innerHTML = newForm.innerHTML.replace(/form-(\d+)/g,`form-${formCount}`);formContainer.appendChild(newForm);totalForms.value = formCount + 1;});
}
  1. 文件上传处理
python">def handle_formset_files(request, formset):"""处理表单集中的文件上传"""for form in formset:if form.is_valid() and form.cleaned_data.get('file'):handle_uploaded_file(request.FILES['file'])

通过本章学习,你应该能够:

  1. 理解表单集的工作原理
  2. 使用内联表单集处理关联数据
  3. 实现动态表单添加和删除
  4. 处理表单集验证和错误

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!


http://www.ppmy.cn/server/153042.html

相关文章

启用Linux防火墙日志记录和分析功能

防火墙的基本功能是阻止来自可疑网络/来源的连接。它会检查所有连接的源地址、目的地址和端口,并决定是否允许或阻止流量。防火墙的每个操作都会记录为日志数据。监控和分析这些日志对于保护您的网络免受攻击至关重要。要这样做,您需要首先启用日志功能。以下是在Linux防火墙…

[创业之路-204]:《华为战略管理法-DSTE实战体系》- 5-平衡记分卡绩效管理

目录 一、平衡计分卡概述 1、平衡计分卡的基本概念 2、平衡计分卡的发展阶段 3、平衡计分卡在华为的应用 4、平衡计分卡的优缺点 五、财务&#xff08;股东&#xff09;、顾客&#xff08;用户&#xff09;、内部运营&#xff08;内部&#xff09;及学习与发展&#xff0…

微服务openfeign配置重试机制

场景&#xff1a; 1、在实际开发中&#xff0c;通过feign调用其他服务&#xff0c;如果出现read-timeout超时、或调用出现异常 2、如上问题&#xff0c;有时候可能是网络速度、网路抖动等原因导致超时异常&#xff0c;并非程序本身错误&#xff0c;所以可以配置openfeign重试…

ALPHA第四章 多态,接口,抽象类

在给出的选项中&#xff0c;错误的叙述是&#xff1a; 子类可以继承父类的构造函数 详细分析&#xff1a; 1. 子类可以继承父类的构造函数 错误的。 在 Java 中&#xff0c;子类不能继承父类的构造函数。构造函数是用来初始化对象的&#xff0c;因此构造函数是不能被继承的&a…

Linux -- 线程的优点、pthread 线程库

目录 线程的优点 pthread 线程库 前言 认识线程库 简单验证线程的独立栈空间 线程的优点 与进程之间的切换相比&#xff0c;线程之间的切换需要操作系统做的工作要少得多。 调度进程时&#xff0c;CPU 中有一个 cache&#xff08;缓存&#xff0c;提高运行效率&#xff0…

Linux RTC 驱动框架

目录 一、实时时钟&#xff08;RTC&#xff09;介绍1.1 概述1.2 功能1.3 应用场景1.4 工作原理1.5 对外接口1.6 常见 RTC 芯片1.7 在 Linux 系统中的应用1.8 注意事项 二、Linux 内核 RTC 驱动框架2.1 相关源码文件介绍2.2 核心数据结构2.2.1 struct rtc_device2.2.2 rtc_class…

memcached 与 redis 的区别?

1、Redis 不仅 仅 支 持 简 单 的 k/v 类型 的 数 据 &#xff0c;同时 还 提 供 list&#xff0c;set&#xff0c;zset&#xff0c;hash等数 据 结 构 的 存 储 。而 memcache 只支 持 简 单 数 据 类 型 &#xff0c;需要 客 户 端 自 己 处 理 复杂对 象 2、 Redis 支持 数 …

对象、函数、原型之间的关系

在 JavaScript 中&#xff0c;对象、函数 和 原型 是三者紧密联系的核心概念。它们共同构成了 JavaScript 中面向对象编程的基石&#xff0c;并通过原型链实现了继承与代码复用。本文将从对象、函数、原型的基础概念到它们之间的关系进行详细的讲解&#xff0c;帮助你理解 Java…