如何让 Django 视图返回表单错误

Posted

技术标签:

【中文标题】如何让 Django 视图返回表单错误【英文标题】:How to get Django view to return form errors 【发布时间】:2014-02-03 05:57:13 【问题描述】:

这是我的看法:

def main_page(request):

    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = User.objects.create_user(
                username=form.clean_data['username'],
                password=form.clean_data['password1'],
                email=form.clean_data['email']
            )
        return HttpResponseRedirect('/')
    else:
        form = RegistrationForm()
        variables = 
            'form': form
        
        return render(request, 'main_page.html', variables)

这是我的 main_page.html:

% if form.errors %
    <p>NOT VALID</p>
    % for errors in form.errors %
         errors 
    % endfor %
% endif %
<form method="post" action="/">% csrf_token %
    <p><label for="id_username">Username:</label> form.username </p>
    <p><label for="id_email">Email Address:</label> form.email </p>
    <p><label for="id_password">Password:</label> form.password1 </p>
    <p><label for="id_retypePassword">Retype Password:</label> form.password2 </p>
    <input type="hidden" name="next" />
    <input type="submit" value="Register" />
</form>

当我转到使用 main_page 视图的 url 时,它只显示表单。当我提交有错误的表单(带有空白字段且没有正确的电子邮件地址)时,它只会将我重定向到同一页面并且不显示任何错误。它甚至没有说“无效”。

当我改变时

% if form.errors %

% if not form.is_valid %

它总是说“无效”(即使这是第一次访问该 url,即使我还没有提交任何内容)。

这是我的注册表:

from django import forms
import re
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist

class RegistrationForm(forms.Form):
    username = forms.CharField(label='Username', max_length=30)
    email = forms.EmailField(label='Email')
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput())
    password2 = forms.CharField(label='Password (Again)', widget=forms.PasswordInput())

    def clean_password2(self):
        if 'password1' in self.cleaned_data:
            password1 = self.cleaned_data['password1']
            password2 = self.cleaned_data['password2']
            if password1 == password2:
                return password2
        raise forms.ValidationError('Passwords do not match.')

        def clean_username(self):
        username = self.cleaned_data['username']
        if not re.search(r'^\w+$', username): #checks if all the characters in username are in the regex. If they aren't, it returns None
            raise forms.ValidationError('Username can only contain alphanumeric characters and the underscore.')
        try:
            User.objects.get(username=username) #this raises an ObjectDoesNotExist exception if it doesn't find a user with that username
        except ObjectDoesNotExist:
            return username #if username doesn't exist, this is good. We can create the username
        raise forms.ValidationError('Username is already taken.')

【问题讨论】:

【参考方案1】:

它会重定向你,因为如果方法是 POST,即使表单无效,你总是返回 HttpResponseRedirect。试试这个:

def main_page(request):
    form = RegistrationForm()
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = User.objects.create_user(
                username=form.clean_data['username'],
                password=form.clean_data['password1'],
                email=form.clean_data['email']
            )
            return HttpResponseRedirect('/')        
    variables = 
        'form': form
    
    return render(request, 'main_page.html', variables)

这样,调用is_valid 的表单实例被传递给模板,并且它有机会显示错误。只有当表单有效时,用户才会被重定向。如果您想花哨,请在重定向之前使用messages framework添加消息。

如果你想让它更简洁一点:

def main_page(request):
    form = RegistrationForm(request.POST or None)
    if form.is_valid():
        user = User.objects.create_user(
            username=form.clean_data['username'],
            password=form.clean_data['password1'],
            email=form.clean_data['email']
        )
        return HttpResponseRedirect('/')        
    variables = 
        'form': form
    
    return render(request, 'main_page.html', variables)

【讨论】:

对,这就是我最初所拥有的,但是“如果 request.method == 'POST'”但表单无效会发生什么?它仍然需要返回一些东西,对吗?我尝试了您的视图,如果表单无效,它会给出 ValueError,错误表示“main_page 视图没有返回 HttpResponse 对象”。 从我的理解中,我希望它始终重定向到主页,即使表单无效,因为这样我就可以在主页上显示表单中的错误,对吗?如果它是有效的,那很好。如果不是,它仍然很好,因为它会重定向到带有 form.errors 的主页,这是我的想法。这很奇怪,因为即使在我点击提交表单错误(使用我发布的视图)之后,模板也不会显示表单错误,所以就像视图没有意识到 request.method == 'POST'。 嗯,if request.method == "POST"not form.is_valid,下面只是继续执行,最后返回render 函数的结果,所以它应该可以工作...? 如果出现错误,您不想重定向,因为通过重定向,您会丢失所有状态:HTTP is stateless。在浏览器将您的表单 POST 到服务器并且服务器以重定向响应后,浏览器不会 POST 到新的 url;它将发出一个 GET 请求。 啊,你是对的!当我说“对,这就是我最初拥有的”时,结果发现这并不是我最初拥有的。我最初有一个“else:variables = 'form':form return ....”,这就是为什么当request.method = =“POST”而不是form.is_valid时它给了我一个ValueError。好的,谢谢。【参考方案2】:

让你的视图变成这样:

if form.is_valid():
    pass
    # actions
else:
    # form instance will have errors so we pass it into template
    return render(request, 'template.html', 'form': form)

在模板中你可以遍历 form.errors 或简单:

 forms.as_p 

【讨论】:

对,但是如果 request.method != "POST" 也有可能(因为它是我的主页,所以如果这是用户第一次访问主页,那么他没有'还没有提交任何东西,所以 request.method != "POST" 对吗? 是的,请求方法是 GET。我建议您看一下基于 django 类的视图。这是一个没有脏if request.method == POST等的表单验证的快速示例:pastebin.com/D5YwFLpP如果用户第一次打开页面方法get将显示表单。如果用户提交表单方法post 将对其进行验证并做出适当的操作。【参考方案3】:

您可以重新格式化视图以在控制台中显示表单错误,如下所示

def main_page(request):

    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = User.objects.create_user(
                username=form.clean_data['username'],
                password=form.clean_data['password1'],
                email=form.clean_data['email']
            )
        else:
            print(form.errors)
            return HttpResponse("Form Validation Error")

        return HttpResponseRedirect('/')
    else:
        form = RegistrationForm()
        variables = 
            'form': form
        
        return render(request, 'main_page.html', variables)


与往常一样,保持上述缩进。如果表单有任何错误,它将显示在控制台中,如

<ul class="errorlist"><li>date<ul class="errorlist"><li>Enter a valid date.</li></ul></li></ul>

希望对你有帮助

【讨论】:

以上是关于如何让 Django 视图返回表单错误的主要内容,如果未能解决你的问题,请参考以下文章

如何让来自 Ajax 的 Django 表单错误出现在用户屏幕上?

在 Django 中,如何通过错误返回 File 输入的值?

在 Django 中返回 AJAX 请求的表单错误

如何在我的 Django 应用程序的“评论”视图中修复此错误?

使用ajax将它们作为json后如何循环遍历django表单错误

Django Crispy 表单 - 更新视图的内联表单集“ManagementForm 数据”错误