python-3.x 当我不在Django模板中的表单域上循环时,如何显示错误消息?

unftdfkk  于 2023-02-17  发布在  Python
关注(0)|答案(1)|浏览(92)

当我尝试提交一个空表单时,表单没有显示错误消息,但是当我在views.py中循环字段错误时,我可以看到错误。我该如何克服这个问题?
template(已更新)

{% block formcontent %}
    {{form.non_field_errors}}
    <div class="row">
        <div class="col">
            {{form.username.label_tag}} {{form.username}} {{form.username.errors|striptags}}
        </div>
    </div><br>
    <div class="row">
        <div class="col">
            {{form.first_name.label_tag}} {{form.first_name}} {{form.first_name.errors|striptags}}
        </div>
        <div class="col">
            {{form.last_name.label_tag}} {{form.last_name}} {{form.last_name.errors|striptags}}
        </div>
    </div><br>
    <div class="row">
        <div class="col">
            {{form.email.label_tag}} {{form.email}} {{form.email.errors|striptags}}
        </div>
    </div><br>
    <div class="row">
        <div class="col">
            {{form.location.label_tag}} {{form.location}} {{form.location.errors|striptags}}
        </div>
        <div class="col">
            {{form.designation.label_tag}} {{form.designation}} {{form.designation.errors|striptags}}
        </div>
    </div><br>
    <div class="row">
        <div class="col">
            {{form.password1.label_tag}} {{form.password1}} {{form.password1.errors|striptags}}
        </div>
        <div class="col">
            {{form.password2.label_tag}} {{form.password2}} {{form.password2.errors|striptags}}
        </div>
    </div><br>
{% endblock formcontent %}

编辑1:(更新)

class MyRegistrationForm(UserCreationForm):
password1=forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2=forms.CharField(label='Confirm Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
    model=MyRegistration
    fields=['username', 'first_name', 'last_name', 'email', 'location', 'designation']
    widgets={
        'username':forms.TextInput(attrs={'class':'form-control'}),
        'first_name':forms.TextInput(attrs={'class':'form-control'}),
        'last_name':forms.TextInput(attrs={'class':'form-control'}),
        'email':forms.EmailInput(attrs={'class':'form-control'}),
        'location':forms.Select(attrs={'class':'form-select'}),
        'designation':forms.TextInput(attrs={'class':'form-control'}),
    }

def clean_username(self):
    username = self.cleaned_data.get('username')
    if not username:
        raise ValidationError('Username is required!')
    else:
        try:
            MyRegistration.objects.get(username=username)
            raise ValidationError('This username already exists!', code='username_exists')
        except MyRegistration.DoesNotExist:
            pass
    return username

def clean_email(self):
    email=self.cleaned_data.get('email')
    if not email:
        raise ValidationError('Email is required!')
    else:
        try:
            MyRegistration.objects.get(email=email)
            raise ValidationError('This email already exists!', code='email_exists')
        except MyRegistration.DoesNotExist:
            pass
    return email

def clean_first_name(self):
    first_name=self.cleaned_data.get('first_name')
    if not first_name:
        raise ValidationError('First-name is required!')
    return first_name

def clean_last_name(self):
    last_name=self.cleaned_data.get('last_name')
    if not last_name:
        raise ValidationError('Last-name is required!')
    return last_name

def clean_location(self):
    location=self.cleaned_data.get('location')
    if not location:
        raise ValidationError('Location is required!')
    return location

def clean_designation(self):
    designation=self.cleaned_data.get('designation')
    if not designation:
        raise ValidationError('Designation is required!')
    return designation

我真的不知道我在模板中的代码有什么问题。我已经检查过了,Django文档建议用同样的方法来处理表单没有循环的场景。
编辑二:
models.py:

class MyRegistration(AbstractBaseUser, PermissionsMixin):
    location_list=[
        ('Solapur', 'Solapur'),
        ('Dhule', 'Dhule'),
        ('Other', 'Other'),
        ]
    username=models.CharField(max_length=10, unique=True)
    email=models.EmailField(unique=True)
    first_name=models.CharField(max_length=150)
    last_name=models.CharField(max_length=150)
    location=models.CharField(max_length=10, choices=location_list, default=None)
    designation=models.CharField(max_length=70)
    is_active=models.BooleanField()
    is_staff=models.BooleanField(default=False)
    start_date=models.DateTimeField(default=timezone.now)
    last_login=models.DateTimeField(null=True)

    USERNAME_FIELD='username'
    REQUIRED_FIELDS=['email', 'first_name', 'last_name', 'location', 'designation']
    objects=FirstManager()
    def __str__(self):
        return self.first_name

views.py:(已更新)

def signup(request):
print('1')
if request.user.is_authenticated:
    print('2')
    if request.method=='POST':
        print('3')
        if request.POST.get('password1')==request.POST.get('password2'):
            print('4')
            fm=MyRegistrationForm(request.POST)
            for field in fm:
                print("Field Error:", field.name,  field.errors)
            if fm.is_valid():
                print('6')
                fm.save()
                messages.success(request, 'Registered successfully!!')
            fm=MyRegistrationForm()
            print('7')
            cur_user=request.user
            return render(request, 'account/signup.html', {'form':fm, 'cur_user':cur_user})
    else:
        fm=MyRegistrationForm()
        cur_user=request.user
        return render(request, 'account/signup.html', {'form':fm, 'cur_user':cur_user})
else:
    return HttpResponseRedirect('/')
hmae6n7t

hmae6n7t1#

clean方法中引发ValidationError时,这些错误将添加到窗体的non_field_errors属性中,这就是为什么在特定字段上使用form.email.errors和其他errors属性时不会呈现任何内容的原因。
您应该在呈现窗体之前呈现form.non_field_errors,这样您也可以看到这些错误。
然而,为了解决您的问题,我宁愿选择将每个字段的验证拆分为特定的方法clean_<field_name>。例如,对于用户名字段:

def clean_username(self):
    username = self.cleaned_data.get('username')
    if not username:
        raise ValidationError('Username is required!')
    else:
        try:
            un=MyRegistration.objects.get(username=self.instance.username)
            raise ValidationError('This username already exists!')
        except MyRegistration.DoesNotExist:
            pass

    # Make sure you return the value of the data in 
    # the clean_<field_name> methods
    return username

对于其他字段也是如此。这样做应该可以修复代码,但这里有一些其他的建议:

  • ValidationErrors取整时使用代码。例如:raise ValidationError('This username already exists', code='username_exists')
  • 看看django-crispy包,它可以用最少的代码处理表单的HTML呈现
  • 您可以在模型中为唯一字段(如用户名)和必填字段设置约束。这进一步防止了没有使用表单添加数据的用户(如管理员)添加重复的用户名或空值。这也意味着许多自定义验证代码将是不必要的。
    **EDIT #1:**使用instance从提交的表单中获取值是错误的。由于此表单专门用于创建目的,因为注册是创建新用户,因此instance将始终为空。instance仅在更新模型示例时填充数据。

您应该将instance的使用替换为从self.cleaned_data dict获取表单数据。例如:

# Instead of:
username = self.instance.username
# Use:
username = self.cleaned_data.get('username')

**EDIT #2:**作者添加视图代码后。

问题可能出在您的视图代码中。另外,没有必要比较password1password2,因为UserCreationForm已经为您的做了这件事。

核心问题是,如果表单无效,您需要重新呈现相同的表单,而不是创建另一个示例。

def signup(request):
    print('1')
    if request.user.is_authenticated:
        print('2')
        if request.method=='POST':
            print('3')
            form = MyRegistrationForm(request.POST)
            if form.is_valid():
                print('4')
                form.save()
                messages.success(request, 'Registered successfully!!')
            # If you do this, you always render the empty form
            # without the errors
            # fm=MyRegistrationForm()
            print('7')
            cur_user=request.user
            return render(
                request, 'account/signup.html', 
                {'form': form, 'cur_user':cur_user}
            )
        else:
            form = MyRegistrationForm()
            cur_user=request.user
            return render(
                request, 'account/signup.html', 
                {'form':form, 'cur_user':cur_user}
            )
    else:
        return HttpResponseRedirect('/')

其他一些建议:

  • 如果这是注册视图,你可能不需要检查用户是否通过了身份验证。新用户如何创建一个帐户呢?然而,如果这是需要的,@login_required装饰器可能更适合。
  • 如果成功,您需要重定向到成功URL。对于成功的情况,不要使用render,只有在处理GET方法或需要重新呈现表单以显示验证错误时才使用。

相关问题