You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Form clean()中cleaned_data.get返回None引发AttributeError求助

Django表单clean()方法AttributeError问题排查

问题描述

按照Django官方文档编写表单代码,在clean()方法中校验name和email是否均以小写字母s开头,但cleaned_data.get(field name)返回None,触发错误:AttributeError: 'NoneType' object has no attribute 'startswith'。

错误信息

AttributeError at /feedback3/
'NoneType' object has no attribute 'startswith'
Request Method:   POST
Request URL:  http://localhost:8000/feedback3/
Django Version:   4.1.2
Exception Type:   AttributeError
Exception Value:  
'NoneType' object has no attribute 'startswith'
Exception Location:   C:\Users\singh\Desktop\Journey\Django Journey\Geeky Shows\Eleven\Feedback3\forms.py, line 72, in clean
Raised during:    Feedback3.views.feedback
Python Executable:    C:\Users\singh\AppData\Local\Programs\Python\Python310\python.exe
Python Version:   3.10.7

关联代码

原forms.py代码

from django import forms
from django.core.exceptions import ValidationError

class GirlsFeedback(forms.Form):
    name = forms.CharField(label = 'Enter Your Name', label_suffix = " ", required=True, disabled=False, min_length = 5, max_length = 100, strip=True)

    password = forms.CharField(label='Enter Your Password', label_suffix = " ", required=True, disabled=False,
    min_length=8, max_length=10, help_text="Minimum 8 and Maximum 10 characters are allowed.", widget=forms.PasswordInput)

    email = forms.EmailField(error_messages={'required': 'Email is mandatory'})

    def clean(self):
        cleaned_data = super().clean()
        name = cleaned_data.get('name')
        email = cleaned_data.get('email')
        if name.startswith('s') and email.startswith('s') !=True:
            raise ValidationError('Name and email both should start with a lowercase s')

views.py代码

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import GirlsFeedback

# Create your views here.

def success(request):
    return render(request, 'Feedback3/success.html', {'name':name,'email':email})

def feedback(request):
    if request.method == 'POST':
        var = GirlsFeedback(request.POST)
        if var.is_valid():
            global name, password, email 
            name = var.cleaned_data['name']
            password = var.cleaned_data['password']
            email = var.cleaned_data['email']
            return HttpResponseRedirect('/feedback3/success')
    else:
        var = GirlsFeedback()
    return render(request, 'Feedback3/feedback.html', {'data': var})

feedback.html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Feedback 3</title>
</head>
<body>
    <h1>This is the third feedback page</h1>
    <form action="" method="POST" novalidate>
        {% csrf_token %}
        
        {{data.as_p}}

        <input type="submit" value="Submit Data">

    </form>
</body>
</html>

success.html代码

<!DOCTYPE html>
<html lang="en">


<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Feedback3</title>
</head>


<body>
    <p>Dear {{name}}, Thanks for your feedback. Your feedback has been submitted with the below details </p>
    <p>Name : {{name}}</p>
    <p>Email : {{email}}</p>
</body>


</html>

问题原因

  1. 字段验证失败时,Django不会将该字段加入cleaned_data,此时cleaned_data.get()返回None,直接调用startswith()触发错误。比如name长度不达标、email格式错误时,对应字段会缺失。
  2. 校验逻辑错误:name.startswith('s') and email.startswith('s') !=True 实际是判断“name以s开头但email不以s开头”,和需求“两者都必须以s开头”不符。

解决方法

1. 修正表单clean()方法

先确认字段存在再执行校验,同时修正逻辑:

from django import forms
from django.core.exceptions import ValidationError

class GirlsFeedback(forms.Form):
    name = forms.CharField(label = 'Enter Your Name', label_suffix = " ", required=True, disabled=False, min_length = 5, max_length = 100, strip=True)

    password = forms.CharField(label='Enter Your Password', label_suffix = " ", required=True, disabled=False,
    min_length=8, max_length=10, help_text="Minimum 8 and Maximum 10 characters are allowed.", widget=forms.PasswordInput)

    email = forms.EmailField(error_messages={'required': 'Email is mandatory'})

    def clean(self):
        cleaned_data = super().clean()
        name = cleaned_data.get('name')
        email = cleaned_data.get('email')
        
        # 仅当两个字段都通过基础验证时,执行联合校验
        if name and email:
            # 检查两者是否都以s开头
            if not (name.startswith('s') and email.startswith('s')):
                raise ValidationError('Name and email both should start with a lowercase s')
        
        return cleaned_data

2. 修复views.py全局变量问题

全局变量传递数据不安全,改用session存储:

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import GirlsFeedback

def success(request):
    name = request.session.get('name')
    email = request.session.get('email')
    # 清理临时数据
    del request.session['name']
    del request.session['email']
    return render(request, 'Feedback3/success.html', {'name':name,'email':email})

def feedback(request):
    if request.method == 'POST':
        var = GirlsFeedback(request.POST)
        if var.is_valid():
            name = var.cleaned_data['name']
            email = var.cleaned_data['email']
            # 存入session
            request.session['name'] = name
            request.session['email'] = email
            return HttpResponseRedirect('/feedback3/success')
    else:
        var = GirlsFeedback()
    return render(request, 'Feedback3/feedback.html', {'data': var})

额外说明

  • super().clean()执行后,字段验证失败的错误已自动添加到表单,联合校验只需处理字段都合法的场景。
  • 务必在clean()方法末尾返回cleaned_data,遵循Django表单验证规范。

内容的提问来源于stack exchange,提问作者Sujit_Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:10:33