每天40分玩转Django:Django表单

Django表单

一、今日学习内容概述

学习模块 重要程度 预计学时
表单基础与创建 ⭐⭐⭐⭐⭐ 1.5小时
表单验证机制 ⭐⭐⭐⭐⭐ 2小时
CSRF保护机制 ⭐⭐⭐⭐⭐ 1.5小时
表单渲染与处理 ⭐⭐⭐⭐ 1小时

二、Django表单基础知识

Django的表单处理是Web应用程序中最重要的部分之一,它提供了一种方便的方式来处理用户输入数据。表单不仅包括HTML表单,还包括验证逻辑和数据处理逻辑。

2.1 创建表单类

让我们通过一个实际的例子来学习Django表单。假设我们要创建一个用户注册表单:

python 复制代码
# forms.py
from django import forms

class UserRegistrationForm(forms.Form):
    username = forms.CharField(
        label='用户名',
        max_length=100,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': '请输入用户名'
        })
    )
    email = forms.EmailField(
        label='电子邮件',
        widget=forms.EmailInput(attrs={
            'class': 'form-control',
            'placeholder': '请输入邮箱'
        })
    )
    password = forms.CharField(
        label='密码',
        min_length=6,
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '请输入密码'
        })
    )
    confirm_password = forms.CharField(
        label='确认密码',
        min_length=6,
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '请再次输入密码'
        })
    )
    
    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        confirm_password = cleaned_data.get('confirm_password')
        
        if password and confirm_password and password != confirm_password:
            raise forms.ValidationError('两次输入的密码不匹配')
        
        return cleaned_data

2.2 视图处理表单

python 复制代码
# views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegistrationForm

def register(request):
    if request.method == 'POST':
        form = UserRegistrationForm(request.POST)
        if form.is_valid():
            # 获取清理后的数据
            cleaned_data = form.cleaned_data
            # 这里可以添加用户注册逻辑
            messages.success(request, '注册成功!')
            return redirect('login')
    else:
        form = UserRegistrationForm()
    
    return render(request, 'registration/register.html', {'form': form})

2.3 模板展示表单

html 复制代码
<!-- templates/registration/register.html -->
{% extends 'base.html' %}

{% block content %}
<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">
                    <h3 class="text-center">用户注册</h3>
                </div>
                <div class="card-body">
                    <form method="post" novalidate>
                        {% csrf_token %}
                        
                        {% if form.non_field_errors %}
                        <div class="alert alert-danger">
                            {% for error in form.non_field_errors %}
                                {{ error }}
                            {% endfor %}
                        </div>
                        {% endif %}
                        
                        {% for field in form %}
                        <div class="form-group mb-3">
                            {{ field.label_tag }}
                            {{ field }}
                            {% if field.errors %}
                            <div class="alert alert-danger mt-1">
                                {{ field.errors }}
                            </div>
                            {% endif %}
                        </div>
                        {% endfor %}
                        
                        <button type="submit" class="btn btn-primary w-100">注册</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

三、表单验证机制

Django的表单验证分为多个层次:

  1. 字段级验证
  2. 表单级验证
  3. 自定义验证器

3.1 字段级验证

python 复制代码
# forms.py
from django import forms
import re

def validate_chinese_phone(value):
    pattern = r'^1[3-9]\d{9}$'
    if not re.match(pattern, value):
        raise forms.ValidationError('请输入有效的中国手机号码')

class ContactForm(forms.Form):
    name = forms.CharField(
        min_length=2,
        max_length=50,
        error_messages={
            'required': '姓名不能为空',
            'min_length': '姓名长度不能小于2个字符',
            'max_length': '姓名长度不能超过50个字符'
        }
    )
    phone = forms.CharField(
        validators=[validate_chinese_phone],
        error_messages={
            'required': '手机号码不能为空'
        }
    )
    
    def clean_name(self):
        name = self.cleaned_data['name']
        if name.isdigit():
            raise forms.ValidationError('姓名不能为纯数字')
        return name

3.2 表单级验证

python 复制代码
def clean(self):
    cleaned_data = super().clean()
    name = cleaned_data.get('name')
    phone = cleaned_data.get('phone')
    
    # 示例:检查特定组合条件
    if name and phone:
        if name.lower() in phone:
            raise forms.ValidationError('手机号码不能包含姓名')
    
    return cleaned_data

四、CSRF保护机制

CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的Web安全漏洞。Django内置了CSRF保护机制。

4.1 CSRF中间件配置

python 复制代码
# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',  # CSRF中间件
    ...
]

4.2 CSRF令牌使用

在模板中使用CSRF令牌:

html 复制代码
<form method="post">
    {% csrf_token %}
    <!-- 表单字段 -->
</form>

对于AJAX请求,需要在请求头中包含CSRF令牌:

javascript 复制代码
// 获取CSRF令牌
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;

// 发送AJAX请求
fetch('/api/endpoint/', {
    method: 'POST',
    headers: {
        'X-CSRFToken': csrftoken,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(data)
})

五、ModelForm使用

ModelForm是Django提供的一种特殊表单类,它可以直接从模型创建表单。

python 复制代码
# models.py
from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200, verbose_name='标题')
    content = models.TextField(verbose_name='内容')
    published_date = models.DateTimeField(auto_now_add=True, verbose_name='发布时间')
    
    class Meta:
        verbose_name = '文章'
        verbose_name_plural = verbose_name

# forms.py
from django.forms import ModelForm
from .models import Article

class ArticleForm(ModelForm):
    class Meta:
        model = Article
        fields = ['title', 'content']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'content': forms.Textarea(attrs={'class': 'form-control'})
        }
        error_messages = {
            'title': {
                'required': '标题不能为空',
                'max_length': '标题长度不能超过200个字符'
            },
            'content': {
                'required': '内容不能为空'
            }
        }

六、表单处理流程图

七、表单高级特性

7.1 动态表单字段

python 复制代码
class DynamicForm(forms.Form):
    def __init__(self, *args, **kwargs):
        extra_fields = kwargs.pop('extra_fields', {})
        super().__init__(*args, **kwargs)
        
        for field_name, field_type in extra_fields.items():
            self.fields[field_name] = field_type

7.2 表单集(Formset)使用

python 复制代码
from django.forms import formset_factory

class ItemForm(forms.Form):
    name = forms.CharField(max_length=100)
    quantity = forms.IntegerField(min_value=0)

# 创建表单集
ItemFormSet = formset_factory(ItemForm, extra=2, max_num=10)

# 视图中使用
def manage_items(request):
    if request.method == 'POST':
        formset = ItemFormSet(request.POST)
        if formset.is_valid():
            for form in formset:
                if form.cleaned_data:
                    # 处理每个表单的数据
                    pass
    else:
        formset = ItemFormSet()
    return render(request, 'manage_items.html', {'formset': formset})

八、常见问题与解决方案

  1. 表单验证失败但没有显示错误信息

    • 确保在模板中正确显示错误信息
    • 检查表单的clean方法是否正确抛出ValidationError
  2. CSRF验证失败

    • 检查是否包含csrf_token
    • 确认CSRF中间件已启用
    • 检查会话cookie是否正常工作
  3. 文件上传失败

    • 确保表单包含enctype="multipart/form-data"
    • 检查文件大小是否超过限制
    • 验证文件类型是否允许

九、今日总结

  1. 学习了Django表单的基本概念和创建方法
  2. 掌握了表单验证机制和自定义验证方法
  3. 理解了CSRF保护的重要性和实现方式
  4. 学习了ModelForm的使用和表单集的高级特性

十、练习任务

  1. 创建一个包含文件上传的表单,实现图片预览功能
  2. 实现一个动态生成字段的表单,并添加相应的验证规则
  3. 使用表单集实现一个订单系统的表单,包含多个商品项
  4. 为表单添加自定义的JavaScript验证和实时反馈

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

相关推荐
鸟哥大大7 分钟前
【Python】pypinyin-汉字拼音转换工具
python·自然语言处理
sjsjsbbsbsn11 分钟前
Spring Boot定时任务原理
java·spring boot·后端
jiugie15 分钟前
MongoDB学习
数据库·python·mongodb
hzulwy18 分钟前
MongoDB应用设计调优
数据库·mongodb
我爱松子鱼37 分钟前
MySQL 单表访问方法详解
数据库·mysql
阿尔法波37 分钟前
python与pycharm如何设置文件夹为源代码根目录
开发语言·python·pycharm
xing25161 小时前
pytest下allure
开发语言·python·pytest
眸笑丶1 小时前
使用 Python 调用 Ollama API 并调用 deepseek-r1:8b 模型
开发语言·python
我们的五年1 小时前
MySQL存储引擎:选择与应用
数据库·mysql
计算机毕设指导61 小时前
基于Springboot学生宿舍水电信息管理系统【附源码】
java·spring boot·后端·mysql·spring·tomcat·maven