在Web开发的日常里,用户输入处理是绕不开的核心环节——从简单的留言板、登录注册,到复杂的内容编辑页,都需要一套能兼顾效率、安全、易用的表单方案。django官方自带的Form系统,恰恰完美适配了这个需求:既能手动搭灵活的HTML表单,也能和Model无缝对接生成CRUD页面,甚至还能批量处理表单数据。
今天这篇就带大家从基础摸透,再到常用高级用法踩坑避雷~
📚 先划重点:本文覆盖这些内容
- django Form的核心能力是什么
- 从零搭一个能跑的完整基础Form
- 常用字段、自定义验证、Widget美化
- 最省力的ModelForm快速开发
- 表单安全的基础细节
很多新手可能觉得“手写HTML表单+后端写正则验证不就行了?”,但实际用django Form会发现它帮你省了90%的重复工作:
- 自动生成HTML标签:不用写重复的
input/select
- 全链路数据验证:从字段格式到业务逻辑,前端提示后端兜底
- 错误自动处理与展示:不用自己组装错误信息传到模板
- Model一键绑定:写一个Form就能搞定增删改查
- CSRF安全自动保护:只要按规范写,不用额外处理核心令牌
2.1 定义表单类
和定义django Model类似,Form也是通过继承forms.Form,定义类属性作为表单字段:
# app/forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100, label="你的昵称")
email = forms.EmailField(label="常用邮箱")
subject = forms.CharField(max_length=200, label="留言主题")
message = forms.CharField(widget=forms.Textarea, label="详细内容")
# required=False默认不勾选,也不会校验必填
subscribe = forms.BooleanField(required=False, label="订阅我们的更新")
2.2 视图层处理逻辑
视图是连接表单和数据的桥梁,核心要分清楚GET/POST两种请求:
# app/views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import ContactForm
def contact_view(request):
if request.method == "POST":
# 用POST数据实例化表单(绑定数据)
form = ContactForm(request.POST)
# 先做全链路验证
if form.is_valid():
# 验证通过后,取cleaned_data(已转成Python对应类型的安全数据)
name = form.cleaned_data["name"]
email = form.cleaned_data["email"]
# 处理数据:比如发邮件、存数据库
# send_contact_mail(name, email, ...)
messages.success(request, "留言发送成功!")
return redirect("contact") # 成功后重定向避免重复提交
else:
# GET请求返回空表单(未绑定数据)
form = ContactForm()
# 不管POST/GET失败,都把当前表单(空的或带错误的)传给模板
return render(request, "contact.html", {"form": form})
2.3 模板层渲染
django提供了三种快捷渲染方式,也支持手动拆字段自定义样式:
<!-- templates/contact.html -->
<form method="post">
{% csrf_token %} <!-- 必加!否则会被django拦截 -->
<!-- 快捷方式1:as_p 每个字段包在<p>里 -->
{{ form.as_p }}
<!-- 快捷方式2:as_ul 包在<li>里(记得加<ul>标签) -->
<!-- <ul>{{ form.as_ul }}</ul> -->
<!-- 快捷方式3:as_table 包在<tr><td>里(记得加<table>) -->
<!-- <table>{{ form.as_table }}</table> -->
<button type="submit" class="btn btn-primary">发送留言</button>
</form>
三、常用高级功能
常用字段
上面的例子用了基本的文本、邮箱、文本域,还有很多实用的:
# app/forms.py
from django import forms
class UserProfileForm(forms.Form):
# 带长度限制和提示的用户名
username = forms.CharField(
max_length=150, min_length=3,
label="用户名", help_text="3-150个字符,支持字母数字下划线"
)
# 密码输入框(隐藏内容)
password = forms.CharField(widget=forms.PasswordInput, min_length=8)
# 单选下拉框
gender = forms.ChoiceField(
choices=[("M", "男"), ("F", "女"), ("O", "其他")],
label="性别"
)
# 多选复选框(默认是列表,用CheckboxSelectMultiple转成复选)
hobbies = forms.MultipleChoiceField(
choices=[("reading", "阅读"), ("sports", "运动"), ("music", "音乐")],
widget=forms.CheckboxSelectMultiple, label="兴趣爱好"
)
# HTML5原生日期选择器
birth_date = forms.DateField(
widget=forms.DateInput(attrs={"type": "date"}), label="出生日期"
)
Widget是字段的“HTML外衣”,可以通过attrs加类名、占位符等:
# app/forms.py
from django import forms
class SearchForm(forms.Form):
query = forms.CharField(
max_length=200,
widget=forms.TextInput(attrs={
"class": "form-control", # 适配Bootstrap
"placeholder": "搜索你感兴趣的内容...",
"id": "global-search"
}),
label="" # 隐藏标签
)
3.2 表单验证
django的验证是分层的,从字段类型→字段自带规则→自定义字段验证→整体表单验证:
自定义字段验证
格式是def clean_字段名(self):,最后必须返回清洗后的字段值:
# app/forms.py
from django import forms
from .models import Article # 假设你有Article模型
class ArticleForm(forms.Form):
title = forms.CharField(max_length=200, label="文章标题")
content = forms.CharField(widget=forms.Textarea, label="正文")
def clean_title(self):
title = self.cleaned_data["title"]
# 规则1:至少5个字符
if len(title) < 5:
raise forms.ValidationError("标题太短啦,至少5个字符")
# 规则2:不能和已有的重复
if Article.objects.filter(title=title).exists():
raise forms.ValidationError("这个标题已经被用过了")
return title # 必须返回!
整体表单验证
格式是def clean(self):,可以跨字段校验:
class ArticleForm(forms.Form):
# ... 上面的字段 ...
def clean(self):
# 先调用父类的clean,获取所有清洗后的字段
cleaned_data = super().clean()
title = cleaned_data.get("title")
content = cleaned_data.get("content")
# 规则:标题不能完全出现在正文开头
if title and content and content.startswith(title):
raise forms.ValidationError("正文开头不能直接复制标题")
return cleaned_data
如果你的表单是为了增删改某个Model的数据,那直接用ModelForm就行,它会自动继承Model的字段类型、长度限制、验证规则:
4.1 基本定义
# app/forms.py
from django import forms
from .models import Article
class ArticleModelForm(forms.ModelForm):
class Meta: # 必须用这个内部类配置
model = Article # 绑定的Model
fields = ["title", "content", "category", "status"] # 要显示的字段(推荐显式写)
# 或者 exclude = ["author", "created_at"] # 排除某些字段
# 覆盖Model默认的Widget
widgets = {
"content": forms.Textarea(attrs={"class": "form-control", "rows": 10}),
"status": forms.Select(attrs={"class": "form-select"}),
}
# 覆盖默认的标签
labels = {
"category": "文章分类",
}
4.2 视图层增删改
新增(自动保存Model)
# app/views.py
from django.contrib.auth.decorators import login_required
@login_required
def create_article(request):
if request.method == "POST":
form = ArticleModelForm(request.POST)
if form.is_valid():
# commit=False:先不存数据库,用来补充Model里没在表单显示的字段
article = form.save(commit=False)
article.author = request.user # 补充当前登录用户
article.save() # 真正存数据库
messages.success(request, "文章发布成功!")
return redirect("article_detail", pk=article.pk)
else:
form = ArticleModelForm()
return render(request, "create_article.html", {"form": form})
编辑(绑定实例)
@login_required
def edit_article(request, pk):
# 先获取要编辑的文章,找不到404
article = get_object_or_404(Article, pk=pk)
# 检查权限
if article.author != request.user:
messages.error(request, "您没有权限编辑这篇文章")
return redirect("article_list")
if request.method == "POST":
# 绑定数据+实例,这样save()就是更新而不是新增
form = ArticleModelForm(request.POST, instance=article)
if form.is_valid():
form.save()
messages.success(request, "文章更新成功!")
return redirect("article_detail", pk=article.pk)
else:
# GET请求绑定实例,自动填充已有内容
form = ArticleModelForm(instance=article)
return render(request, "edit_article.html", {"form": form, "article": article})
五、表单安全的基础细节
5.1 CSRF保护
django默认开启CSRF中间件,所有POST表单必须加{% csrf_token %}模板标签,否则会返回403 Forbidden。
如果是AJAX请求,可以通过以下方式加令牌:
// 从Cookie中读取CSRF令牌
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
// 全局配置AJAX
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
5.2 永远不要信任用户输入
哪怕django帮你做了验证,业务逻辑里最好再加一层:比如过滤垃圾信息关键词、限制链接数量等。
六、总结
django Form系统是Web开发的“瑞士军刀”,上手简单但功能强大:
- 日常简单表单用
forms.Form,灵活可控
- 绑定Model的CRUD用
ModelForm,节省90%的代码
- 验证规则分层清晰,满足各种业务需求
- 自带CSRF保护,不用手动处理核心安全
如果想深入了解,可以去看django官方文档的Form章节哦~