全书目录

第十四篇:Django 完全指南 —— 中央行政城区宇宙

第十章:表单 —— 市民填表、窗口验表、合格后入档

1 分钟 277 字 第 284 / 962 个阅读单元

HTML 表单谁都能写,但 Django 的强项在于:

表单结构、服务端校验、错误回显、模型绑定,能走成一条完整流程。

先写一个 ModelForm

py
from django import forms
from .models import Permit

class PermitForm(forms.ModelForm):
    class Meta:
        model = Permit
        fields = ["title", "department", "description"]

    def clean_title(self):
        title = self.cleaned_data["title"].strip()
        if len(title) < 4:
            raise forms.ValidationError("事项标题至少 4 个字符")
        return title

再写创建视图:

py
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render

from .forms import PermitForm

@login_required
def create(request):
    if request.method == "POST":
        form = PermitForm(request.POST)
        if form.is_valid():
            permit = form.save(commit=False)
            permit.created_by = request.user
            permit.save()
            return redirect("permits:detail", pk=permit.pk)
    else:
        form = PermitForm()

    return render(request, "permits/form.html", {"form": form})

模板:

html
<!-- templates/permits/form.html -->
{% extends "base.html" %}

{% block content %}
  <h2>新建许可证申请</h2>
  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">提交申请</button>
  </form>
{% endblock %}

表单处理流程图:

text
GET /permits/create/
    │
    ▼
显示空白表单
    │
    ▼
用户填写并 POST
    │
    ▼
form = PermitForm(request.POST)
    │
    ▼
form.is_valid()
   ├── 否:回显错误
   └── 是:保存数据
    │
    ▼
redirect 到详情页

这里有三个必须形成肌肉记忆的点。

第一,{% csrf_token %} 不是装饰品,是防跨站请求伪造的重要机制。

第二,成功提交后通常走 POST / Redirect / GET,不要直接在 POST 成功后原地渲染成功页,否则刷新容易重复提交。

第三,表单校验一定要以服务端为准。前端校验可以提升体验,但不能替代 Django 表单或模型层的校验。