Django KeyError at /register/ - django

I have a registration that let users register and i'm having difficulty fixing it.
The problem is when a user submits a single field instead of the whole form for example an email . I get this error
KeyError at /register/
password
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _get_errors
115. self.full_clean()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in full_clean
271. self._clean_form()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _clean_form
299. self.cleaned_data = self.clean()
File "C:\o\17\mysite\pet\forms.py" in clean
31. if self.cleaned_data['password'] != self.cleaned_data['password1']:
Exception Type: KeyError at /register/
Exception Value: password
I tried to fix this solution using if . If user has a submitted a username or any other required field , process the form otherwise redisplay the original form.
but I still get the same error.
This is my edited views.py (at the bottom of the page is my original RegistrationForm)
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
if username:
email=form.cleaned_data['email']
if email:
password=form.cleaned_data['password']
if password:
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
How can I fix this error and also how could I display an error message on the other fields that the user didn't fill out like "Error Missing Field , Please Fill this Field".
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
My forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
"That user is already taken , please select another ")
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
My models.py
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100, blank=True)
birthday = models.DateField(blank=True,null=True)
def __unicode__(self):
return self.name

Problem is with your clean(). In clean(), you are trying to access field password on form's cleaned_data. password will only be available on cleaned_data if the user has filled this field. So, you must check that password is there in cleaned_data before trying to access it.
Changing your clean():
def clean(self):
if 'password' in self.cleaned_data and 'password1' in self.cleaned_data and self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
You can provide a keyword argument error_messages on form field for showing error message like "Error Missing Field , Please Fill this Field".
class SomeForm(forms.Form):
name = forms.CharField(error_messages={'required':'Error Missing Field , Please Fill this Field'})
There is a bug in your view.
is_valid() populates errors on the form but this same form instance must be sent to the template so that you can access the errors on the form's fields.
But in your view, you have only one call to render() which gets called even in case of an invalid form on a post request. And in this render(), you are creating a new instance of form. So, this new form which you are sending to template will not have any errors.
So, making slight modification to your view:
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
form = UserRegistration() #This will be used in GET request
if request.method =='POST':
form = UserRegistration(request.POST) #This will be used in POST request
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': form})
Notice in your view, I have added form=UserRegistration() before checking if its POST request, and have added the comment at two places where we are instantiating UserRegistration. And then in render(), you should send this form.
Then your {{form.username.errors}} will work.

I just modified your forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean(self):
cleaned_data = super(UserRegistration, self).clean()
username = cleaned_data.get("username")
password = cleaned_data.get("password")
password1 = cleaned_data.get("password1")
#check if username exist
user = User.objects.filter(username=username)
if user:
raise forms.ValidationError(
"That user is already taken , please select another ")
#check password
if password != password1:
raise forms.ValidationError(
"Your current and confirm password do not match.")
return cleaned_data

Related

Django - user should have is_active = False but it is showing active in admin

My custom signup view has the user's is_active set to False. They use an emailed authorized token to set is_active to True. However, immediately after I sign up as a new user, I log into the admin page as a superuser and I can see that my new user has active checked off.
views
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
user.is_teacher = True
user.is_staff = True
user.is_active = False
to_email = form.cleaned_data.get('email')
user.username = to_email # make the username the same as the email
user.save()
group = Group.objects.get(name='teacher')
user.groups.add(group)
current_site = get_current_site(request)
# use sendgrid api for email
sendgrid_client = SendGridAPIClient(
api_key=os.environ.get('SENDGRID_API_KEY'))
from_email = From("me#email.com")
to_email = To(to_email)
subject = "Activate your SmartMark Account"
active_link = render_to_string('account/acc_active_email_link.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
html_text = f'Hello {user}<br/><p>Registration email</p>{active_link}'
html_content = HtmlContent(html_text)
mail = Mail(from_email, to_email, subject,
html_content)
response = sendgrid_client.send(message=mail)
return redirect(reverse('accounts:account_activation_sent'))
else:
form = CustomUserCreationForm()
return render(request, 'account/signup.html', {'form': form})
def account_activation_sent(request):
return render(request, 'account/account_activation_sent.html')
def activate(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = CustomUser.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
# calls check_token function but user is already set to active - email and token
# were never used.
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
return redirect('home')
else:
return render(request, 'account/account_activation_invalid.html')
CustomUser model
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
is_teacher = models.BooleanField('teacher status', default=False)
def __str__(self):
return self.username
Form
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = get_user_model()
fields = ('email', 'first_name', 'last_name')
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
def clean_email(self):
value = self.cleaned_data["email"]
if not value:
raise forms.ValidationError('An Email address is required.')
check_users = CustomUser.objects.filter(email__iexact=value)
if check_users:
raise forms.ValidationError('This email is already in use.')
return value
I am using Django's built in authentication. I am expecting the Active in the admin panel to be not checked off. I also tried moving the user.is_active=False to after the user.save() but this did not change the behaviour. I know from looking at my inital migrations file that the default for is_active is True but I would think that my signup view would override this
Edit
I thought I had fixed this by changing to user=form.save(commit=False) but it's happening again. New sign ups are automatically active.
First I changed my form save to:
user=form.save(commit=False)
However, it appears that the problem is that when I email the authorization token, the email recipient is checking the url for spam. By checking that the token url is a valid, the token is getting validated. I add a POST form such that the token is not checked until the user submits the form.

Django Form not saving for Custom User Model

I have a register user form which is doing all the validation as expected. However, it is not saving. I am not able to figure out the reason. How do I debug it ? Any help ? I am a newbie to forms and formviews any good document with example would really help me.
class RegisterForm(forms.ModelForm):
phone_number = forms.IntegerField(required=True)
password1 = forms.CharField(widget=forms.PasswordInput())
password2 = forms.CharField(widget=forms.PasswordInput())
country_code = forms.IntegerField()
#schools = school.objects.all()
#school_name = forms.ModelChoiceField(queryset=school.objects.distinct())
MIN_LENGTH = 4
class Meta:
model = User
fields = ['username','country_code','phone_number', 'password1', 'password2',
'full_name' ]
def clean_phone_number(self):
phone_number = self.data.get('phone_number')
print(phone_number)
if User.objects.filter(phone_number=phone_number).exists():
raise forms.ValidationError(
_("Another user with this phone number already exists"))
if len(phone_number) == 10 and phone_number.isdigit():
pass
else:
raise forms.ValidationError(
_("Invalid Phone Number"))
return phone_number
def save(self, *args, **kwargs):
print("saving")
user = super(RegisterForm, self).save(*args, **kwargs)
user.set_password(self.cleaned_data['password1'])
print('Saving user with country_code', user.country_code)
user.save()
return user
Views.py
class RegisterView(SuccessMessageMixin, FormView):
template_name = 'register-2.html'
form_class = RegisterForm
success_message = "One-Time password sent to your registered mobile number.\
The verification code is valid for 10 minutes."
def form_valid(self, form):
full_name=self.request.POST["full_name"]
user = form.save()
print(user.id)
username = self.request.POST['username']
password = self.request.POST['password1']
user = authenticate(username=username, password=password)
kwargs = {'user': user}
self.request.method = 'POST'
print("User created")
The print in clean_phone_number works however, save does not work
I had issue in the my form. One of the field was disabled and the value was not captured because of that.
However to identify that I used
def form_invalid(self,form):
# Add action to invalid form phase
messages.error(self.request, form.errors)
return self.render_to_response(self.get_context_data(form=form))

Email forms do not match in Django Custom-User registration

I'm setting up a custom-user registration form to create an account on my Django project. I feel I'm missing something very simple that keeps me from registering for some reason.
My registration form demands 4 fields to be filled before a new user can register. Of these 4 fields, two are just a confirmation of the email address.
Here is a copy of my form.py:
class UserRegisterForm(forms.ModelForm):
username = forms.CharField(label='Username')
email = forms.EmailField(label='Email Address')
email2 = forms.EmailField(label='Confirm Email')
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = CustomUser
fields = ['username', 'email', 'email2', 'password']
def clean_email(self):
email = self.cleaned_data.get('email')
email2 = self.cleaned_data.get('email2')
if email != email2:
raise forms.ValidationError("Emails do not match")
And here is a copy of my view.py:
def register_view(request):
next = request.GET.get('next')
form = UserRegisterForm(request.POST or None)
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get('password')
user.set_password(password)
user.save()
new_user = authenticate(username=user.username, password=password)
login(request, new_user)
if next:
return redirect(next)
return redirect('/home/')
context = {'form':form, "title":"register"}
return render(request, "register.html", context)
Here is my html file:
<h2><center><font color="white">Register Here:</font></center></h2>
<form method="POST"><center>
{% csrf_token %}
{{form}}
<input type="submit" />
</center></form>
Whenever I try to register as a new user, my form validation error is raised as is says that my two emails do not match (I copy-paste them to make sure they are identical).
I feel I'm missing something that is right under my nose...
Cheers to all of you and thank you very much.
try this
def register_view(request):
next = request.GET.get('next')
form = UserRegisterForm(request.POST or None)
if form.is_valid():
email = form.cleaned_data.get('email')
email1 = form.cleaned_data.get('email1')
if email1 == email
user = form.save(commit=False)
password = form.cleaned_data.get('password')
user.set_password(password)
user.save()
new_user = authenticate(username=user.username, password=password)
login(request, new_user)
if next:
return redirect(next)
else:
….
def clean(self):
cleaned_data = super(UserRegisterForm, self).clean()
email = cleaned_data.get('email')
email2 = cleaned_data.get('email2')
if email != email2:
self.add_error("email", "Emails do not match")
The problem is that in clean_email method you have email2 to be always None. To compare two or more fields use clean method

Django Register Form 'AnonymousUser' object has no attribute 'backend'

I have the following register view that enters a new user.
I want it to enter the new user and then log in automatically.
It saves through the User record but returns this error when trying to login:
'AnonymousUser' object has no attribute 'backend'
views.py
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST, error_class=DivErrorList)
if form.is_valid():
form.save()
new_user = authenticate(username=request.POST['username'],password=request.POST['password'])
login(request, new_user)
return HttpResponseRedirect('/production/')
else:
form = UserRegisterForm(error_class=DivErrorList)
return render(request,'register.html', {
'form': form,
})
forms.py
class UserRegisterForm(forms.ModelForm):
class Meta:
model = User
fields = ('username','first_name','last_name','email','password')
password_compare = forms.CharField(max_length=128)
def __init__(self, *args, **kwargs):
super(UserRegisterForm, self).__init__(*args, **kwargs)
self.fields['password_compare'].label = 'Password Again'
self.fields['password'].help_text = ''
self.fields['first_name'].label = 'First Name'
self.fields['last_name'].label = 'Last Name'
self.fields['email'].label = 'E-mail Address'
def clean(self):
cleaned_data = self.cleaned_data
password1 = cleaned_data.get('password', None)
password2 = cleaned_data.get('password_compare', None)
if not (password1):
error_msg = u'This field is required.'
self._errors['password'] = self.error_class([error_msg])
if not (password2):
error_msg = u'This field is required.'
self._errors['password_compare'] = self.error_class([error_msg])
# password fields must match
if password1 != password2:
error_msg = u'Password doesn\'t match the confirmation.'
self._errors['password'] = self.error_class([error_msg])
del cleaned_data['password']
# cannot have a username already existing
try:
existing_user = User.objects.get(username=cleaned_data.get('username'))
error_msg = u'Username already exists.'
self._errors['username'] = self.error_class([error_msg])
del cleaned_data['username']
return cleaned_data
except User.DoesNotExist:
return cleaned_data
Your user will never authenticate, because you're saving the password in plain text - and authenticate expects a hashed password. You should call user.set_password(password) on the newly-created user object before saving it to the db - see the built-in UserCreationForm.
I had the same error for a newly registering user and it left me frustrated for an hour.
There was a piece of code that tried to log user in right after the registration.
Usually it worked just fine, but not this time.
def attempt_login(self, email, password):
user = authenticate(username=email, password=password)
login(self.request, user)
return user
It seemed that authenticate returned None, and then calling login with None caused this exception. But I was sure the User has been created after registration.
Finally, I realized that this particular user's login was longer than 30 characters, and the form field had no validation. The login would get truncated in the database, and therefore authenticate was called for non-existent login.

Django form.is_valid() not calling method clean_<fieldname>

I copied a simple example of a user registration page in Django 1.0 Web Site Development. I have defined the following form:
class RegistrationForm(forms.Form):
username = forms.CharField(label=u'Username', max_length=30)
email = forms.EmailField(label=u'Email')
password1 = forms.CharField(
label=u'Password',
widget=forms.PasswordInput()
)
password2 = forms.CharField(
label=u'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):
print "Validating username..."
username = self.cleaned_data['username']
if not re.search(r'^\w+', username):
raise forms.ValidationError('Username can only contain '
'alphanumeric characters and the underscore.')
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError('Username is already taken')
In the case where a username is already taken, the field is validated using the normal form validation and my custom clean method is not called. When the form is submitted to register_page, form.is_valid() returns True.
Is there something missing that needs to be done in order for Django to know to call the clean_ methods?
def register_page(request):
if request.method == 'POST':
print "Posted to registration form"
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('/')
else:
form = RegistrationForm()
return render_to_response(
'users/registration.html',
context_instance=RequestContext(request, {
'form' : form
})
In case anybody else gets here via google and the above answer doesn't help:
I had this same problem and it turned out to be I was not setting exclude as a tuple in my forms meta:
class MyFormClass(ModelForm):
class Meta:
exclude = ('type_detail') #wrong
instead of:
class MyFormClass(ModelForm):
class Meta:
exclude = ('type_detail', ) #right
This was truly puzzling. I restored a auto-save version of forms.py and it magically started working, yet there is no difference that I can discern between the code snippet above, and the restored file.
Short answer: "Programmer Error"