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>
问题原因
- 字段验证失败时,Django不会将该字段加入
cleaned_data,此时cleaned_data.get()返回None,直接调用startswith()触发错误。比如name长度不达标、email格式错误时,对应字段会缺失。 - 校验逻辑错误:
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
相关产品推荐
相关产品推荐

