'WSGIRequest' object has no attribute 'post' with custom registration form - python

I have looked at a lot of posts that had similar issues and the answers did nothing for my code.
I am using a custom registration form for a site I'm working on that makes email required. most of the code in it is based off of the one built in to django. I have tried to create a new form class based on django.contrib.auth.forms.UserCreationForm and still get the same error.
The form based on the one in django
class UserCreateFrom(UserCreationForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("That email is already in use"),
'password_mismatch': _("The two password fields didn't match."),
}
email = forms.EmailField(label=_("Email Address"),
required=True,
help_text="Required. Your Email Address for password resets, and other emails from us")
def clean_email(self):
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
the form currently in use
class UserCreateFrom(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("That email is already in use"),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.#+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"#/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"#/./+/-/_ characters.")
}
)
email = forms.EmailField(label=_("Email Address"),
required=True,
help_text="Required. Your Email Address for password resets, and other emails from us")
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("username",)
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages['duplicate_username'],
code='duplicate_username',
)
def clean_email(self):
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
def clean_password2(self):
password1 = self.cleaned_data["password1"]
password2 = self.cleaned_data["password2"]
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(UserCreateFrom, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
the view, I have not been able to work on if the form is valid since I cant get it to work with no data UserCreateFrom is my custom registration form imported from froms.py in the same app.
#sensitive_post_parameters()
#csrf_protect
#never_cache
def register(request):
"""
Allow registration of new users
:param request:
:return:
"""
context = {}
form = UserCreateFrom(data=request.post)
context.update({'form': form})
if request.method == 'POST' and form.is_valid():
return render(request, 'test.html', context)
else:
return render(request, 'register.html', context)
if I switch form = UserCreateFrom(data=request.post) to form = UserCreateFrom(request) I get 'WSGIRequest' object has no attribute 'get' error, but this way at least errors in the template right where the form is called via `{{ form }}, and not the view.

The data attribute is called request.POST.
But you should move that into the block that checks the method.

Related

Why I get "KeyError" exception in django instead of "This field is required" exception on the form validation

I'm new to Django, I have a registration form, Everything works fine If I fill all fields and when I don't fill all the fields. But when I submit a form without a username field I get a "Key Error" instead of "This field is required" Exception since I have declared the field is required on the form class.
forms.py
class UserRegistration(forms.ModelForm):
first_name = forms.CharField(label='First Name', max_length=50)
last_name = forms.CharField(label='Last Name', max_length=50)
username = forms.CharField(label='Username', max_length=50)
email = forms.EmailField(label='Email', max_length=50)
password = forms.CharField(label='Password', widget=forms.PasswordInput, max_length=50, validators = [validators.MinLengthValidator(6)])
password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput, max_length=50)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password', 'password2')
def clean_username(self):
username = self.cleaned_data['username']
email = self.cleaned_data['email']
if username and User.objects.filter(username=username).exclude(email=email).count():
raise forms.ValidationError('This username address is already in use.')
return username
def clean_email(self):
email = self.cleaned_data['email']
username = self.cleaned_data['username']
if email and User.objects.filter(email=email).exclude(username=username).count():
raise forms.ValidationError('This email address is already in use.')
return email
def clean_password(self):
password = self.cleaned_data['password']
if len(password) < 6:
raise forms.ValidationError("Password is too short")
return password
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('Passwords don\'t match.')
return cd['password2']
views.py
def register(request):
if request.method == 'POST':
form = UserRegistration(request.POST)
if form.is_valid():
new_user = form.save(commit=False)
new_user.set_password(
form.cleaned_data.get('password')
)
new_user.save()
return render(request, 'authapp/register_done.html')
else:
return render(request, 'authapp/register.html', {'form':form})
else:
form = UserRegistration()
context = {
"form": form
}
return render(request, 'authapp/register.html', context=context)
Error Traceback
Error Page Screenshot
Request Information Post data
When creating Form, update the username field with required and Null
Yes, by default required will be True but it is a constraint for the DB side while the 'null' field is used when any widget is must from UI side
username = forms.CharField(label='Username', max_length=50,required=True,null=False)
And about error you got : username validator is saving empty name so empty data is accessed and used in email validation
After googling and researching "KeyError" Exception, I have found that the error is caused by accessing a dictionary value with a key 'username' that doesn't exist, hence the KeyError. So it's more of a programming error than Django itself. The solution is to check for the key if it exists before accessing it or use
username = self.cleaned_data.get('username')
instead of
username = self.cleaned_data['username']
according to https://www.journaldev.com/33497/python-keyerror-exception-handling-examples#:~:text=We%20can%20avoid%20KeyError%20by,when%20the%20key%20is%20missing.

New users can't log in. Django

I'm using a view to create new users in Django. And then I have another view to log them in.
But when I create a user, and I try to log in with authenticate(username=username_post, password=password_post), I get None, so it displays in the template 'Wrong username or password.'.
In my database, I see new registers every time I create a new user. However, as the password is encrypted, I can't say if the problem is the login view, or the register view.
However, the super user that I created through the command line after I first installed django, is able to login with no problem, so that makes me thing that the problem is when I create the user.
These are my Login and Register views:
class Login(View):
form = LoginForm()
message = None
template = 'settings/blog_login.html'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated():
return redirect('settings:index')
return render(request, self.template, self.get_context())
def post(self, request, *args, **kwargs):
username_post = request.POST['username']
password_post = request.POST['password']
user = authenticate(username=username_post, password=password_post)
if user is not None:
login(request, user)
return redirect('settings:index')
else:
self.message = 'Wrong username or password.'
return render(request, self.template, self.get_context())
def get_context(self):
return {'form': self.form, 'message': self.message}
class Register(CreateView):
success_url = reverse_lazy('settings:login')
model = User
template_name = 'settings/blog_register.html'
form_class = RegisterForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.set_password(self.object.password)
self.object.save()
return HttpResponseRedirect(self.get_success_url())
And these are my forms:
class LoginForm(forms.Form):
username = forms.CharField(max_length=20, label='Username')
password = forms.CharField(label='Password', widget=forms.PasswordInput())
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=20, label='Username')
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.',
'unique': 'Username already used.',
'invalid': 'Not valid username.'})
password2 = forms.CharField(label='Retype password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.'})
email = forms.EmailField(error_messages={'required': 'Required field.',
'invalid': 'Invalid email.'})
def clean(self):
clean_data = super(RegisterForm, self).clean()
password1 = clean_data.get('password1')
password2 = clean_data.get('password2')
if password1 != password2:
raise forms.ValidationError('Passwords are different.')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(
username=username).exists():
raise forms.ValidationError('Email already used.')
return email
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email')
Please, let me know if you need more info.
You don't have a field called 'password' in your form - you just have 'password1' and 'password2' - so nothing is saved to the model object's actual password field. So, when you do self.object.set_password(self.object.password), you're actually setting a blank password.
Instead, you should get the value from your form's password1 field:
self.object.set_password(self.form.cleaned_data['password1'])

Django. Best way to have unique email in User model?

I have a UserProfile model to add some things to my User model and one thing I want to do is have unique email for users so I added an email attribute to my UserProfile model and set it to unique=True like this :
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name="profile")
email = models.EmailField(unique=True)
avatar = models.ForeignKey(Avatar)
...
I created a custom form for the registration to add some infos directly to my UserProfile :
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30, label="Pseudo")
password1 = forms.CharField(widget=forms.PasswordInput, label="Password")
password2 = forms.CharField(widget=forms.PasswordInput, label="Confirmez pwd")
email = forms.EmailField(widget=forms.EmailInput, label="E-mail")
avatar = AvatarChoiceField(widget=forms.RadioSelect, queryset=Avatar.objects.all(), label="Avatar")
def clean_username(self):
username = self.cleaned_data.get('username')
if User.objects.filter(username=username).exists():
raise forms.ValidationError("This username is already used")
return username
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 != password2:
raise forms.ValidationError("Your passwords do not match")
return password1
def clean_email(self):
email = self.cleaned_data.get('email')
if UserProfile.objects.filter(email=email).exists():
raise forms.ValidationError("This email is already used")
return email
And then in my views.py I treat my form like that :
def create_user(request):
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
username = form.clean_username()
email = form.clean_email()
password = form.clean_password2()
username = form.cleaned_data['username']
avatar = form.cleaned_data['avatar']
user = User.objects.create_user(username=username, password=password)
user.save()
user_profile = UserProfile(user=user, email=email, avatar=avatar)
user_profile.save()
else:
form = CreateUserForm()
return render(request, 'accounts/create.html', locals())
Finally I used the email of the form for my UserProfile model and not for my User model. And by this way I have a unique email for my users. And it's working.
Am I doing it right or is there a better way to achieve what I want ?
You are on the right track, the only thing that doesn't look right is that you shouldn't call clean method manually like this:
# These are not needed in your view method
username = form.clean_username()
email = form.clean_email()
password = form.clean_password2()
They are already called by form.is_valid(). See this SO question for details.

Get username in url [Django] [mongoengine]

I am using django 1.7 with mongoengine. I have created a class Projects :
class Projects(Document):
user = ReferenceField(User, reverse_delete_rule=CASCADE)
p_name = StringField(max_length=70, required=True)
author = StringField(max_length=70, required=True)
url = StringField(max_length=200, required=True)
short_discription = StringField(max_length=100, required=True)
long_discription = StringField()
logo_url = StringField(max_length=200, required=False)
logo = ImageField(size=(250, 250, True))
tags = TaggableManager()
def __unicode__(self):
return self.p_name
def save(self, *args, **kwargs):
self.p_name = self.p_name
return super(Projects, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('view_project', args=[self.p_name])
def get_edit_url(self):
return reverse('update', args=[self.id])
def get_delete_url(self):
return reverse('delete', args=[self.id])
and i am referencing and storing user in my mongodb through my views :
class new_project(CreateView):
model = Projects
form_class = NewProjectForm
success_url = reverse_lazy('registered')
def get_template_names(self):
return["new_project.html"]
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super(new_project, self).form_valid(form)
and mongodb JSON format looks like this :
"user" : ObjectId("54db3e5d7818f4253e5da0db"),
I want to to create user profile where they can see their all projects, for that i created a view :
class UserProjectsListView(ListView):
model = Projects
context_object_name = "project"
def get_template_names(self):
return ["view_user.html"]
def get_queryset(self):
return self.model.objects.filter(user=self.kwargs['pk'])
and my urls.py :
url(r'^new_project/', new_project.as_view(),name='new_project'),
url(r'^project/(?P<pk>[\w\d]+)', view_project.as_view(), name='view_project'),
url(r'^user/(?P<pk>[\w\d]+)/$', UserProjectsListView.as_view(), name='detail'),
The problem with this is that i have to use the object id only in my url, but want to use username instead. Because on the template it renders only username not the object id.
Does anyone know how to use username in urls instead of object id, because rendering object id on template would not be good for security purpose also.
my user creation form :
class UserCreationForm(forms.Form):
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("A user with that email already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.#+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"#/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"#/./+/-/_ characters.")})
email = forms.EmailField(label=_("Email"), max_length=254,
help_text=_("Required valid email. 254 characters or fewer."),
error_messages={
'invalid': _("This value may contain only valid email address.")})
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages['duplicate_username'],
code='duplicate_username',
)
def clean_email(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self):
user = User._default_manager.create_user(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'],
password=self.cleaned_data["password1"])
return user
I also want to get data from three tables and i have used dev instead of class:
def UserProjectsListView(request, pk):
return render_to_response('view_user.html', {
'tuorial' : Tutorial.objects.filter(user=pk),
'question' : Question.objects.filter(user=pk),
'project': Project.objects.filter(user=pk),
})
P.S. Thanks in advance.
If MongoEngine can't simulate joins, it is very simple to do this in two separate queries:
def get_queryset(self):
user = User.objects.get(username=self.kwargs['username'])
return self.model.objects(user=user.id)

Django 1.6 - 'AnonymousUser' object has no attribute 'backend'

I'm trying to create a simple user registration in Django and I get this error. I've looked it up here on stackoverflow: 'AnonymousUser' object has no attribute 'backend', Django Register Form 'AnonymousUser' object has no attribute 'backend' and tried calling authentication before login. But I keep getting this error.
Can anyone please help me with this?
Here is the traceback
Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
57. return view_func(*args, **kwargs)
File "/Users/harisaghadi/Dropbox/Senior Project/Django Tutorials/mysite/meddy1/views.py" in signup_user
51. login(request, new_user)
File "/Library/Python/2.7/site-packages/django/contrib/auth/__init__.py" in login
85. request.session[BACKEND_SESSION_KEY] = user.backend
File "/Library/Python/2.7/site-packages/django/utils/functional.py" in inner
214. return func(self._wrapped, *args)
Exception Type: AttributeError at /meddy1/signup/
Exception Value: 'AnonymousUser' object has no attribute 'backend'
Here is my forms.py
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Please enter a valid email address so we can reach you.'}))
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.#+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"#/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"#/./+/-/_ characters.")})
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("username",)
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages['duplicate_username'],
code='duplicate_username',
)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
userProfile = DoctorSeeker(user=user, name=name, email=email)
userProfile.save()
return user
views.py
def index(request):
return HttpResponse("Welcome to Meddy")
# -------------------- Authentication ----------------------
def signup(request):
return render(request, 'meddy1/signup.html', {})
#csrf_exempt
def signup_user(request):
if request.method == 'POST':
form = UserCreationForm(request.POST,request.FILES)
if form.is_valid():
new_user = authenticate(username=request.POST['username'],password=request.POST['password1'])
login(request, new_user)
return HttpResponseRedirect(reverse('index'))
else:
form = UserCreationForm()
return render(request, "meddy1/signup.html", {'form': form,'usersignup':True})
def login_user(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username,password=password)
if user:
return render(request, 'meddy1/index.html')
else:
return HttpResponseRedirect('/')
def logout_user(request):
logout(request)
return HttpResponseRedirect('/')
models.py
class DoctorSeeker(models.Model):
name = models.CharField(max_length=30)
email = models.EmailField()
user = models.ForeignKey(User, unique=True)
def __unicode__(self):
return u"%s %s" % (self.name, self.email)
Since you found the similar posts, i take it, you understand, that your authenticate does not really authenticate anything. It fails for some reason.
I understand that the view you are showing us is trying to accomplish 2 things- create user and log him in? Right? Since its name is signup_user.
Well. You have UserCreationForm, but you do not save it. So you cant really authenticate an user, that does not yet exist in the system. Save your form first, then call authenticate.

Categories