英文:
display form errors. Django
问题
我有注册表单。我不知道如何显示错误。我试过在models.py
中尝试,我有唯一的错误,但它们不会显示,我还在forms.py
中进行了自定义验证,检查密码是否匹配以及密码的一些规则,但也不起作用。所以问题是,如何显示验证错误?
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, AbstractUser
class User(AbstractUser):
username = models.CharField(max_length=100, unique=True, error_messages={
'unique': "This username has already been registered."})
password = models.CharField(max_length=200, unique=False)
email = models.EmailField(unique=True, error_messages={
'unique': "This email has already been registered."})
phoneNumber = models.CharField(max_length=12, unique=True, error_messages={
'unique': "This phone number has already been registered."})
first_name = None
last_name = None
forms.py
from django.forms import ModelForm, ValidationError
from django import forms
from .models import User
class LogInForm(forms.Form):
# ...
class SignUpForm(ModelForm):
# ...
def clean(self):
# ...
views.py
# ...
def signUp(request):
# ...
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
# ...
else:
messages.error(request, "afasgasg")
return redirect('signUp')
else:
form = SignUpForm()
return render(request, 'signUp.html', {"form": form})
# ...
signUp.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">
<link rel="stylesheet" href="{% static 'css/signUp.css' %}" />
<title>Sign up</title>
</head>
<body>
<div class="container">
<form class="form" method="post">
<h1 class="title">Sign up</h1>
{% csrf_token %}
{% for field in form %}
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<span class="message-error"> {{ error }} </span>
{% endfor %}
{% endif %}
{% endfor %}
{% if form.non_field_errors %}
{% for non_field_error in form.non_field_errors %}
<span class="message-error"> {{ non_field_error }} </span>
{% endfor %}
{% endif %}
<label for="confirm-valid" class="label-check">
<input type="checkbox" id="confirm-valid" required> I've checked the correctness of the entered data
</label>
<label for="confirm-agreement" class="label-check">
<input type="checkbox" id="confirm-agreement" required> I agree with the user agreement
</label>
<button class="form-button" type="submit">Sign up</button>
</form>
</div>
</body>
</html>
我尝试了raise ValidationError()
和 add_error()
,但它们不起作用。我有一个登录表单,它运行得很好,所有错误都会显示,一切都正常。我知道可以在注册表单中使用messages.error()
,但我需要为特定字段显示错误,例如,如果电子邮件已经注册过。
我可以重写我的注册视图,错误会显示,但在这种情况下,用户将在重新加载页面后每次都发送POST请求。现在,只有在用户点击表单中的提交按钮后才会发送POST请求,但因此表单不会保存其错误。
编辑
我在重新加载页面后发送POST请求,这样做可以吗?
(未提供可用于查看的链接)
英文:
I have sign up form. I don't know how I can display errors. I'm trying it from models.py, I have unique errors, but they don't display, I also have custom validation in forms.py, where I'm checking if passwords match and some rules for passwords and it doesn't work either. So, question is, how can I display validation errors?
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, AbstractUser
# Create your models here.
class User(AbstractUser):
username = models.CharField(max_length=100, unique=True, error_messages={
'unique': "This username has already been registered."})
password = models.CharField(max_length=200, unique=False)
email = models.EmailField(unique=True, error_messages={
'unique': "This email has already been registered."})
phoneNumber = models.CharField(max_length=12, unique=True, error_messages={
'unique': "This phone number has already been registered."})
first_name = None
last_name = None
forms.py
from django.forms import ModelForm, ValidationError
from django import forms
from .models import User
class LogInForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Username', 'class': 'form-input'}), required=True)
password = forms.CharField(widget=forms.PasswordInput(
attrs={'placeholder': 'Password', 'class': 'form-input'}), required=True, min_length=8)
class SignUpForm(ModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput(
attrs={"placeholder": "Password"}), min_length=8, required=True)
password2 = forms.CharField(
label='Confirm password', widget=forms.PasswordInput(attrs={"placeholder": "Confirm password"}), min_length=8, required=True)
error_css_class = 'message-error'
error_messages = {
'password_mismatch': 'Passwords must match.',
}
class Meta:
model = User
fields = ('username', 'email', 'phoneNumber', 'password')
widgets = {
"username": forms.TextInput(
attrs={
"placeholder": "Username"
}
),
"email": forms.TextInput(
attrs={
"placeholder": "Email"
}
),
"phoneNumber": forms.TextInput(
attrs={
"placeholder": "Phone number (with a country code) ",
"type": "tel",
"minlength": 12,
"maxlength": 12,
},
),
}
def clean(self):
cleaned_data = super(SignUpForm, self).clean()
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("password2")
if password and confirm_password:
if password != confirm_password:
self.add_error(None, "Passwords don't match")
# raise ValidationError("safasf")
ifNums = False
ifLets = False
for letter in password:
if letter.isalpha():
ifLets = True
if letter.isdigit():
ifNums = True
if ifNums == True and ifLets == True:
break
if ifNums == False or ifLets == False:
self.add_error("password","Your password must contain at least one digit and one letter!")
return cleaned_data
views.py
from django.shortcuts import render
from django.shortcuts import render, redirect
from .forms import LogInForm, SignUpForm
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.hashers import make_password
from django.contrib.auth import authenticate, logout, login as auth_login
from django.contrib import messages
import os
import shutil
# Create your views here.
@login_required
def index(request):
return render(request, 'index.html')
def login(request):
if not request.user.is_authenticated:
logInForm = LogInForm()
if request.method == 'POST':
form = LogInForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(
username=cd['username'], password=cd['password'])
if user is not None:
auth_login(request, user)
return redirect("main")
else:
messages.error(request, "Invalid login or password")
return redirect('login')
else:
form = LogInForm()
return render(request, 'logIn.html', {"form": logInForm})
else:
return redirect('main')
def signUp(request):
if not request.user.is_authenticated:
def createFolder(username):
toFolder = "users/" + username
fromFolder = "scripts/"
os.mkdir(toFolder)
os.mkdir("users/" + username + "/jsons")
if (os.path.exists(fromFolder) and os.path.exists(toFolder)):
for file in os.listdir(fromFolder):
if os.path.isfile(os.path.join(fromFolder, file)):
shutil.copy(os.path.join(fromFolder, file),
os.path.join(toFolder, file))
if os.path.isdir(os.path.join(fromFolder, file)):
os.system(f'rd /S /Q {toFolder}/{file}')
shutil.copytree(os.path.join(fromFolder, file),
os.path.join(toFolder, file))
with open(toFolder + '/config.ini', 'w') as file:
file.write('[Telegram]\n')
file.write('api_id = \n')
file.write('api_hash = \n')
file.write('[VK]\n')
file.write('access_token = \n')
file.write('[INST]\n')
file.write('number = \n')
file.write('password = \n')
file.write('[WA]\n')
file.write('id = \n')
file.write('token = ')
if (request.method == 'POST'):
form = SignUpForm(request.POST)
if (form.is_valid()):
user = form.save(commit=False)
user.password = make_password('password')
user.save()
auth_login(request, user)
createFolder(user.username)
return redirect("main")
else:
messages.error(request, "afasgasg")
return redirect('signUp')
else:
form = SignUpForm()
return render(request, 'signUp.html', {"form": form})
else:
return redirect('main')
def logout_view(request):
logout(request)
return redirect('login')
@login_required
def profile(request):
current_user = request.user
username = current_user.username
email = current_user.email
phoneNumber = current_user.phoneNumber
content = {
'username': username,
'email': email,
'phoneNumber': phoneNumber,
}
return render(request, 'profile.html', context=content)
signUp.html
<!DOCTYPE html>
{% load static %}
<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">
<link rel="stylesheet" href="{% static "css/signUp.css" %}" />
<title>Sign up</title>
</head>
<body>
<div class="container">
<form class="form" method="post">
<h1 class="title">Sign up</h1>
{% csrf_token %}
{% for field in form %}
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<span class="message-error"> {{ error }} </span>
{% endfor %}
{% endif %}
{% endfor %}
{% if form.non_field_errors %}
{% for non_field_error in form.non_field_errors %}
<span class="message-error"> {{ non_field_error }} </span>
{% endfor %}
{% endif %}
<label for="confirm-valid" class="label-check">
<input type="checkbox" id="confirm-valid" required> I've checked the correctness of the entered data
</label>
<label for="confirm-agreement" class="label-check">
<input type="checkbox" id="confirm-agreement" required> I agree with the user agreement
</label>
<button class="form-button" type="submit">Sign up</button>
</form>
</div>
</body>
</html>
I tried this: raise ValidationError(), add_error(). They don't work. I have log in form, and it works fine, all errors display, everything is ok. I know, that I can use messages.error() in sign up form, but I need to display errors for specific fields, for example, for email, if it's been already registered.
I can rewrite my sign up view and errors will display, but in that case user will send post requests every time after reloading page. Now user sends post request only if he pushes submit button in form, but because of it form doesn't save its errors.
EDIT
I send post requests after reloading page, is this ok?
https://drive.google.com/file/d/1DAtk2I6h6XQK0gjMUW8uk7Y8qCjkkG6U/view?usp=sharing
答案1
得分: 2
问题出在您尝试验证后进行重定向:
if (request.method == 'POST'):
form = SignUpForm(request.POST)
if (form.is_valid()):
...
else:
messages.error(request, "afasgasg")
return redirect('signUp') # 这里有问题
这样做会阻止表单显示错误,因为重定向会创建一个新的表单实例。
将您的表单改回引发 ValidationError:
forms.py
class SignUpForm(ModelForm):
...
class Meta:
...
def clean(self):
cleaned_data = super().clean()
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("password2")
if password and confirm_password:
if password != confirm_password:
raise ValidationError("Passwords don't match", code='invalid password')
ifNums = False
ifLets = False
for letter in password:
if letter.isalpha():
ifLets = True
if letter.isdigit():
ifNums = True
if ifNums == True and ifLets == True:
break
if ifNums == False or ifLets == False:
raise ValidationError("Your password must contain at least one digit and one letter!", code='invalid password')
return cleaned_data
此外,您不需要检查错误是否存在,只需在有错误时渲染,或者您可以使用 表单渲染选项:
注册模板
<form class="form" method="post" action="">
<h1 class="title">Sign up</h1>
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
{% for error in field.errors %}
<span class="message-error"> {{ error }} </span>
{% endfor %}
{{ field }}
{% endfor %}
<label for="confirm-valid" class="label-check">
<input type="checkbox" id="confirm-valid" required> I've checked the correctness of the entered data
</label>
<label for="confirm-agreement" class="label-check">
<input type="checkbox" id="confirm-agreement" required> I agree with the user agreement
</label>
<button class="form-button" type="submit">Sign up</button>
</form>
在提交时从 signUp
视图中移除重定向:
def signUp(request):
if not request.user.is_authenticated:
...
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.password = make_password('password')
user.save()
auth_login(request, user)
createFolder(user.username)
return redirect('main')
else:
form = SignUpForm()
return render(request, 'signUp.html', {"form": form})
else:
return redirect('main')
英文:
Problem is because you are redirecting after trying to validate:
if (request.method == 'POST'):
form = SignUpForm(request.POST)
if (form.is_valid()):
...
else:
messages.error(request, "afasgasg")
return redirect('signUp') # problem is here
When you do that, you are not letting the form render the errors, because the redirect will create a new form instance.
Change your forms back to raise ValidationError:
forms.py
class SignUpForm(ModelForm):
...
class Meta:
...
def clean(self):
cleaned_data = super().clean()
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("password2")
if password and confirm_password:
if password != confirm_password:
raise ValidationError(("Passwords don't match"), code='invalid password')
ifNums = False
ifLets = False
for letter in password:
if letter.isalpha():
ifLets = True
if letter.isdigit():
ifNums = True
if ifNums == True and ifLets == True:
break
if ifNums == False or ifLets == False:
raise ValidationError(("Your password must contain at least one digit and one letter!"), code='invalid password')
return cleaned_data
Also, you do not need to check if errors exist, just render when there is one, alternatively you can use form rendering options:
sign up template
<form class="form" method="post" action="">
<h1 class="title">Sign up</h1>
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
{% for error in field.errors %}
<span class="message-error"> {{ error }} </span>
{% endfor %}
{{ field }}
{% endfor %}
<label for="confirm-valid" class="label-check">
<input type="checkbox" id="confirm-valid" required> I've checked the correctness of the entered data
</label>
<label for="confirm-agreement" class="label-check">
<input type="checkbox" id="confirm-agreement" required> I agree with the user agreement
</label>
<button class="form-button" type="submit">Sign up</button>
</form>
remove redirection from signUp
view when posting:
def signUp(request):
if not request.user.is_authenticated:
...
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.password = make_password('password')
user.save()
auth_login(request, user)
createFolder(user.username)
return redirect('main')
else:
form = SignUpForm()
return render(request, 'signUp.html', {"form": form})
else:
return redirect('main')
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论