Display django user creation form error - python

I'm using django built in user creation form which I extended like this
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'placeholder': 'E-mail address'}))
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'username', 'password1', 'password2')
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'])
raise forms.ValidationError('duplicate_email')
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
As you see I've added email validation to check if there is already user with that email (what I don't accept).
The problem is that neither that of those errors are displaying in my template and I don't know why. I've tried with {{form.field.errors}} and even with {{form.errors.values.[i]}} but nothing helps
I looked in auth.forms to check class UserCreationForm and I see that it pass errors to error_messages but I couldn't find the way to display them.
Although all validations (username check, password check, email check) work fine I'd still like to display error above field with error so that user understands why he couldn't create his account.
UPDATE
views.py
def register_user(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
args = {}
args.update(csrf(request))
args['form'] = RegistrationForm()
return render_to_response('user_profile/register.html', args, context_instance=RequestContext(request))
I hope somebody can help me with that.
Thanks

This will work:
def register_user(request):
args = {}
args.update(csrf(request))
if request.method == 'POST':
form = RegistrationForm(request.POST)
args['form'] = form
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
args['form'] = RegistrationForm()
return render_to_response('user_profile/register.html', args, context_instance=RequestContext(request))
The problem with your code was that you was passing an unbound form instance to your template all the time, so you was just overwriting any occured errors.
Look here for a reference: docs

If you are looking at more efficient solution then you should try my below code in views.py file.
Your forms.py code will be same. But it is leakage of validation of password.
# to register auth user
class register_user(View):
template1 = "app_name/register.html" # define templates
template2 = "app_name/login.html"
def get(self, request): # get method
form = RegistrationForm()
return render(request, self.template1, locals())
def post(self, request): # post method
form = RegistrationForm(request.POST) # create form object
if form.is_valid():
print "Form is validated"
user_data = form.save(commit=False)
user_data.save()
return render(request, self.template2, locals())
else:
print "with error"
return render(request, self.template1, locals())
I hope this will help. I'm still working on good practice of Django.

Related

Django: How to log user in right after they had registered with somewhat default UserCreationForm?

I'm trying to log the user in right after they had registered with the app, so that they don't have to manually log in right after. I have created RegisterForm from django's UserCreationForm and it works as it should - it creates an User object if the form is valid, but I don't know how to access that created User object to log it it using the login function, which requires, aside from request, also an user object. Note: I have edited the default User in models.py. This is my code:
class RegisterForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','id':'username', 'aria-describedby':'usernameHelp'})
self.fields['password1'].widget.attrs.update({'class':'form-control','id':'password1', 'aria-describedby':'password1Help'})
self.fields['password2'].widget.attrs.update({'class':'form-control','id':'password2','aria-describedby':'password2Help'})
class Meta:
model = User
fields = ['username', 'password1', 'password2', 'email', 'first_name', 'last_name',
'photo', 'amazon', 'twitter', 'facebook', 'instagram', 'youtube']
widgets = {
'email':EmailInput(attrs={'class':'form-control', 'id':'email', 'aria-describedby':'emailHelp'}),
'first_name':TextInput(attrs={'class':'form-control', 'id':'first_name',}),
'last_name':TextInput(attrs={'class':'form-control','id':'last_name', 'aria-describedby':'nameHelp'}),
'photo':ClearableFileInput(attrs={'class':'form-control','id':'photo', 'aria-describedby':'photoHelp'}),
'amazon':URLInput(attrs={'class':'form-control', 'id':'amazon', 'aria-describedby':'amazonHelp'}),
'twitter':URLInput(attrs={'class':'form-control', 'id':'twitter', 'aria-describedby':'twitterHelp'}),
'facebook':URLInput(attrs={'class':'form-control', 'id':'facebook', 'aria-describedby':'facebookHelp'}),
'instagram':URLInput(attrs={'class':'form-control', 'id':'instagram', 'aria-describedby':'instagramHelp'}),
'youtube':URLInput(attrs={'class':'form-control', 'id':'youtube', 'aria-describedby':'youtubeHelp'})
}
And here is the view:
def register(request):
# POST
if request.method == "POST":
# In addition to our form we must make sure to get the files too, if photo is uploaded
form = RegisterForm(request.POST, request.FILES or None)
if form.is_valid():
form.save()
#user = User.objects.get() ???
#login(request, user)
return HttpResponseRedirect(reverse('index'))
else:
return render(request, "astator/register.html",
{"form":form,
"message":"Something went wrong. Please try filling out the fields again. Make sure that your passwords match and that they satisfy the requirements listed bellow."
})
# GET
else:
form = RegisterForm()
return render(request, "astator/register.html", {"form":form})
In your form you can access your user object so you can do something like that :
if form.is_valid():
user = form.save()
login(request, user)
return HttpResponseRedirect(reverse('index'))
This is explain in the documentation regarding the save method : Django Save Method
Similar to model forms in general, the UserCreationForm returns the user model instance when you save the form.
if form.is_valid():
user = form.save()
login(request, user)
return HttpResponseRedirect(reverse('index'))
you can create a html page then call this classView from that url and you can use django Authentication for more convenience
class LoginForm(AuthenticationForm):
username = UsernameField(widget=forms.TextInput(
attrs={'autofocus': True, 'class': 'form-control'}))
password = forms.CharField(label=_("Password"), strip=False, widget=forms.PasswordInput(
attrs={'autocomplete': 'current-password', 'class': 'form-control'}))

Adding a profile to user in django

Following this :
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone
I am having some trouble with this call:
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
In their example I am guessing this works as is on the signup of a new account because the Profile in their example has all fields that can be blank and null. In my case my profile I am trying to maintain here is called:
class APOUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
institution = models.ForeignKey("mainpage.InstitutionMember", on_delete=models.PROTECT)
gender = models.ForeignKey("mainpage.GenderTable", on_delete=models.PROTECT)
on_site_status = models.ForeignKey("mainpage.SiteStatus", on_delete=models.PROTECT)
refer_to_as = models.TextField(max_length = 30, blank=True) #if the above is custom
room_preference = models.ForeignKey("housing.Room", on_delete=models.PROTECT)
Which has references to ultimately what will be drop downs to select form a form (populated by another table with defaults). So do I remove the #reciever and then just have the users fill out the profile separately somehow after they signup and confirm their account?
I tried to mix my signup form with the profile form... but kept getting an anonmyous user object had no attribute object apouser in the views.py when I try to mix the signup forms and profile forms:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST, instance=request.user.apouser)
if form.is_valid() and profile_form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
profile_form.save()
current_site = get_current_site(request)
mail_subject = 'Activate your APO account.'
message = render_to_string('acc_active_email.html', {
'user': user,
'domain': current_site.domain,
'uid':urlsafe_base64_encode(force_bytes(user.pk)),
'token':account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return redirect('plsactivate')
#return HttpResponse('Please confirm your email address to complete the registration')
#form.save()
#username = form.cleaned_data.get('username')
#raw_password = form.cleaned_data.get('password1')
#user = authenticate(username=username, password=raw_password)
#login(request, user)
#return redirect('/')
else:
form = SignUpForm()
profile_form = ProfileForm(instance=request.user.apouser) #<-- error here
return render(request, 'signup.html', {'form': form, 'profile_form': profile_form})
#return render(request, 'signup.html', {'form': form})
So not sure the proper way to go about what I need. I have my regular user default with the basic stuff the default django signup comes up with. THen I have the APOUser with extra stuff (usually filled out in a profile) but not sure where/how to get users to fill that out.
On signup gives me the anonymous user error
After signup doesn't let the #reciever work because none of the APOUuser stuff is filled out?
Yes, remove the receiver - although it's not the cause of this specific problem, it will cause issues as soon as you fix that
The reason for your error is as it says: since you don't have a logged in user yet, you don't have a profile either. But you don't need one; there is no need to pass an instance argument there.
What you do need to do is to set the user on the result of saving the profile form - in just the she way as you set is_active on the result of saving the user form.
So:
if request.method == 'POST':
form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST,)
if form.is_valid() and profile_form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
...
else:
form = SignUpForm()
profile_form = ProfileForm()
...

Django Check if Username already exists

Here's my forms.py,
class RegistrationForm(UserCreationForm):
class Meta:
model = User
fields = [ 'username', 'first_name', 'password1', 'password2']
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
if commit:
user.save()
return user
In views.py,
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
username = request.POST.get('username')
password = request.POST.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
return redirect(reverse('accounts:profile'))
else:
form = RegistrationForm()
return render(request, 'accounts/reg_form.html', {'form': form})
Right now if i'm using the same username it's raising an error which says "The view accounts.views.register didn't return an HttpResponse object. It returned None instead." How can I fix this issue?
Thank You :)
Django form by default does this for you.
You don't need specific for this.
Beacuse, default User Model provided by django doesn't take duplicate username.
May be some indentation problem
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
. . . .
else:
form = RegistrationForm()
return render(request, 'accounts/reg_form.html', {'form': form})
#^^^^^Indentation here take return statement outside else

How to login either through a mobile no or a email address in django?

I initially used to login using email and password but now want to change it in such a way that we can login using either mobile no or email address and password.I am not able to understand what parts to change in my code as I do not want to delete already existing user and data.
forms.py
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
views.py
class UserFormView(View):
form_class = UserForm
template_name = 'main/registration_form.html'
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
# cleaned (normalized) data
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user.username = email
user.set_password(password)
user.save()
# return user objects if credentials are correct
user = authenticate(username=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
# request.user.username display their username
return redirect('main:register2')
return render(request, self.template_name, {'form': form})
class LoginForm(View):
form_class = UserForm
template_name = 'main/login_form.html'
def get(self, request):
form = self.form_class(None)
if error:
return render(request, self.template_name, {'form': form},
{'error': error})
else:
return render(request, self.template_name, {'form': form})
def post(self, request):
email = request.POST.get('email', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=email, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect("/main/home/")
else:
# Show an error page
error = True
return HttpResponseRedirect("/main/", {'error': error})
Please answer considering the fact that I am new to Django. Thanks in advance :)
In the post method of your view, identify what has the user given you. If it's an email, feed the Django's authenticate() method with the email. If not, then assume it's a phone number (you may also run additional validations in there) and use this in the authentication procedure.
Another approach would be to create a custom authenticate() method, which would look like this:
from django.contrib.auth.backends import ModelBackend
class MobilePhoneOrEmailModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
# the username could be either one of the two
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'mobile_phone': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, username):
try:
return User.objects.get(pk=username)
except User.DoesNotExist:
return None
Let me know if this worked out well for you.
Credits to user user3282276 in this thread as well: Log in user using either email address or username in Django

django default registration module takes unique username but same email

I am using the django default registration module to signup users.
What the module is doing, it is registering users with different username but same email.
How would I be able to send them forgot_password email if it is doing so ??
I wrote this in my views.py so that same email doesnt get registered but this is also not working. users are still getting registered with same email.
def register_user(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
try:
user_present = User.objects.get(username=form.username)
except:
user_present = None
if user_present:
messages.error(request, 'Username already taken')
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html',args)
else:
try:
user_present = User.objects.get(email=form.email)
except:
user_present = None
if user_present:
messages.error(request, 'Your email is already registered.')
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html',args)
else:
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
messages.error(request, 'There were errors in the form. Please fill again.')
return render_to_response('register.html',args)
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html',args)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
Is there any way to add unique=True like this ? :
email = forms.EmailField(required=True,unique=True)
As I understand you are using incorrect values for username and email. You should get them from form like this: form.cleaned_data['username'] and form.cleaned_data['email']. Also I suggest to put this validation into Form itself. Read about clean_fieldname methods here. One more thing: you don't need any uniqueness test for username cause it's by default defined as unique=True so just test for email:
class MyRegistrationForm(UserCreationForm):
# your code here
def clean_email(self):
email = self.cleaned_data.get('email')
if email:
if User.objects.filter(email=email).exists():
raise forms.ValidationError('Your email is not unique.')
return email
Your view now is gonna look much simpler without these uniqueness tests.

Categories

Resources