为啥我的 Django 表单没有引发验证错误?

Posted

技术标签:

【中文标题】为啥我的 Django 表单没有引发验证错误?【英文标题】:Why my Django form is not raising validation error?为什么我的 Django 表单没有引发验证错误? 【发布时间】:2016-09-16 14:19:56 【问题描述】:

以下是我的表单代码:

class ConfirmEmailForm(forms.Form):
    email = forms.EmailField()
    subscribe = forms.IntegerField()
    code = forms.CharField(max_length=80)

    def clean_subscribe(self):
        value = bool(self.cleaned_data['subscribe'])
        self.cleaned_data['subscribe'] = value
        return value

    def clean(self):
        cleaned_data = super(ConfirmEmailForm, self).clean()
        email = cleaned_data['email']
        code = cleaned_data['code']
        user = User.objects.filter(username=email).first()
        if not user:
            raise forms.ValidationError('Email not found')
        self.cleaned_data['user'] = user
        if user.emailverification.is_key_expired():
            raise forms.ValidationError('Link expired, please regenerate')
        if not user.emailverification.key == code:
            raise forms.ValidationError('Invalid Link')
        return cleaned_data

我正在使用此表单进行 GET 请求。现在,当我发送不带email 字段的请求时,我预计错误将在cleaned_data 引发,但它不会引发任何错误,而是在下一行得到KeyError

显然它会引发KeyError,因为它不存在。但我的问题是,为什么super(ConfirmEmailForm, self).clean() 本身没有提出错误。

这是完整的回溯:

Environment:


Request Method: GET
Request URL: http://localhost:8000/user/confirm/?code=g&subscribe=1

Django Version: 1.9.6
Python Version: 3.5.1
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'nightreads',
 'nightreads.posts',
 'nightreads.user_manager']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/views/generic/base.py" in dispatch
  88.         return handler(request, *args, **kwargs)

File "/Users/avi/Documents/code/nightreads/nightreads/user_manager/views.py" in get
  54.         if form.is_valid():

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/forms/forms.py" in is_valid
  161.         return self.is_bound and not self.errors

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/forms/forms.py" in errors
  153.             self.full_clean()

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/forms/forms.py" in full_clean
  363.         self._clean_form()

File "/Users/avi/.virtualenvs/nightreads/lib/python3.5/site-packages/django/forms/forms.py" in _clean_form
  390.             cleaned_data = self.clean()

File "/Users/avi/Documents/code/nightreads/nightreads/user_manager/forms.py" in clean
  30.         email = cleaned_data['email']

Exception Type: KeyError at /user/confirm/
Exception Value: 'email'

为什么会这样?我该如何解决这个问题?访问clean 中经过验证和清理的数据的正确方法是什么?

【问题讨论】:

【参考方案1】:

如果 clean 方法出现错误,它会将其添加到错误列表中,但不会引发错误。

可以找到here这行代码。

        except ValidationError as e:
            self.add_error(name, e)

您可以使用cleaned_data.get('email') 解决它,如果找不到该值,它将返回None - 然后您可以检查它。

【讨论】:

好吧,如果我想访问多个变量,那么我必须获取每个变量,看看它们是否不为空? @avi - 是的,或者只提交整个表单而不是其中的部分 好吧,它是 GET,我不能确定用户没有编辑 URL【参考方案2】:

我认为这是因为当您使用 clean 方法时,此方法引发的任何 ValidationError 都不会与特定字段关联;

尝试创建除此之外的自定义。

【讨论】:

【参考方案3】:

在执行cleaned_data['email'] 之前检查是否存在任何错误。

def clean(self):
    cleaned_data = super(ConfirmEmailForm, self).clean()

    if any(self.errors):
        return self.errors

    email = cleaned_data['email']
    code = cleaned_data['code']

希望这对你有用。

【讨论】:

以上是关于为啥我的 Django 表单没有引发验证错误?的主要内容,如果未能解决你的问题,请参考以下文章

带有初始数据的 Django 禁用字段引发验证错误 [重复]

Django Modelform - 它没有验证,为啥?

显示 ModelForms 的 django 表单验证错误

为啥我会收到这种错误验证错误?

Django奇怪的SlugField验证,在clean()之前没有引发错误,返回了未清理的数据

即使缺少所需的值,Django 验证也会调用 clean()