我有这种形式,几乎是从此official Django doc page上第二个绿色框复制的:
class UserForm(forms.ModelForm):
password1 = forms.CharField(label="Password", widget=forms.PasswordInput())
password2 = forms.CharField(label="Password confirmation", widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserForm, self).save(commit=False)
user.set_password(self.cleaned_data["password2"])
if commit:
user.save()
return user
表单显示正确,并按预期捕获错误(例如“密码不匹配”),但是当尝试使用刚刚创建的用户/密码登录时,它将失败。我可以通过电子邮件重设密码,然后成功登录。
为什么表单无法正确保存密码?
(用户的“活动性”在这里重要吗?)
(此外,我知道已经有一个身份验证表单已经在执行此创建带有密码的用户帐户确认操作,但是我在
https://docs.djangoproject.com/en/1.7/topics/auth/default/#built-in-auth-views
上看不到它)views.py
def create_user_account_success(request):
return render_to_response("registration/create_account_success.html", RequestContext(request))
MIDDLE_YEAR_STR = str(DISCOVERED_MIN_YEAR + ((DISCOVERED_MAX_YEAR - DISCOVERED_MIN_YEAR) // 2))
def create_user_account(request):
context = RequestContext(request)
if(request.method == "POST"):
#Form was filled. Process it.
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if(user_form.is_valid() and profile_form.is_valid()):
#To get a form element, use either
#print(request.POST["password1"])
#or, *after* calling UserForm(data=request.POST) and then
#user_form.is_valid():
#print(user_form.cleaned_data["password1"])
#commit
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if("picture" in request.FILES):
profile.picture = request.FILES["picture"]
profile.save()
return redirect("create_account_success")
else:
#Not a POST. Form hasn't been filled. Get a blank form
global MIDDLE_YEAR_STR
user_form = UserForm()
profile_form = UserProfileForm(initial={
"year_discovered": MIDDLE_YEAR_STR})
context["user_form"] = user_form
context["profile_form"] = profile_form
#Render and display the form
return render_to_response("registration/create_account.html", context)
表格
from django import forms
from django.contrib.auth.models import User
from .models import UserProfile, DISCOVERED_MIN_YEAR, DISCOVERED_MAX_YEAR
class UserForm(forms.ModelForm):
password1 = forms.CharField(label="Password", widget=forms.PasswordInput())
password2 = forms.CharField(label="Password confirmation", widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserForm, self).save(commit=False)
user.set_password(self.cleaned_data["password2"])
if commit:
user.save()
return user
class UserProfileForm(forms.ModelForm):
year_choices = ((x,str(x)) for x in range(DISCOVERED_MIN_YEAR, DISCOVERED_MAX_YEAR+1))
#year_discovered = forms.ChoiceField(choices=year_choices)
year_discovered = forms.IntegerField(required=False,
min_value=DISCOVERED_MIN_YEAR, max_value=DISCOVERED_MAX_YEAR,
widget=forms.Select(choices=year_choices))
#year_discovered = forms.IntegerField(min_value=DISCOVERED_MIN_YEAR, max_value=DISCOVERED_MAX_YEAR)
class Meta:
model = UserProfile
fields = ('year_discovered', 'profile_picture')
create_account.html
{% extends "base.html" %}
{% block title %}Create account{% endblock %}
{% block content %}
<h1>Billy Joel Album Browser: Create account</h1>
{% if registration_was_successful %}
<P>Success!</P>
{% else %}
<form id="user_form" method="post" action="{% url 'create_account' %}"
enctype="multipart/form-data">
{% csrf_token %}
<!-- Display each form. The as_p method wraps each element in a paragraph
(<p>) element. This ensures each element appears on a new line,
making everything look neater. -->
{{ user_form.as_p }}
{{ profile_form.as_p }}
<!-- Provide a button to click to submit the form. -->
<input type="submit" name="submit" value="Register" />
</form>
{% endif %}
{% endblock %}
create_account_succes.html
{% extends "base.html" %}
{% block content %}
<H1>Welcome!</H1>
<P><a href="{% url 'login' %}">Login</A> to proceed.</P>
{% endblock %}
最佳答案
表单和视图之间的密码设置代码重复,这导致了您的问题。
在窗体的save
方法中,您正确地调用user.set_password()
将散列的密码设置到新创建的用户上。但是,然后,您的视图再次调用set_password
:因此,其作用是获取已经散列的密码,再次对其进行散列,然后将双重散列的密码设置给用户。当然,当您登录时,密码不再匹配,因为它已经被重复了两次。
只需从视图中删除两行(user.set_password
和user.save
)。