I used custom form for register users. I want do validation for confirm password.
forms.py:
class RegistrationForm(UserCreationForm):
'''Register for new users'''
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = get_user_model()
fields = {'username', 'password1', 'password2', 'email', 'first_name', 'last_name'}
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
template:
<div class="input-group register">
{{ form.password.errors }}
<label for="id_password1">Password: </label>
{{ form.password1 }}
</div>
<div class="input-group register">
{{ form.password.errors }}
<label for="id_password2">Confirm password: </label>
{{ form.password2 }}
</div>
views.py
def registration_view(request):
context = {}
context.update(csrf(request))
context['form'] = RegistrationForm()
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
newuser = auth.authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password2']
)
auth.login(request, newuser)
return redirect('home')
else:
context['form'] = form
return render(request, '/registration.html', context)
How can I add validation for password(also confirm password)?
You inherit from UserCreationForm [GitHub]. This form already does that for you.
Indeed: the clean_password2 will validate that the two passwords are the same:
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
The _post_clean function will validate that the password is a valid password:
def _post_clean(self):
super()._post_clean()
# Validate the password after self.instance is updated with form data
# by super().
password = self.cleaned_data.get('password2')
if password:
try:
password_validation.validate_password(password, self.instance)
except forms.ValidationError as error:
self.add_error('password2', error)
Finally in the save() it will use .set_password() to set the password. This is necessary, since Django's User model will, like any good user model, hash the password.
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
You thus should not interfere with these. You here only want to add first_name and last_name. So you can add that logic with:
class RegistrationForm(UserCreationForm):
'''Register for new users'''
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = get_user_model()
fields = ['username', 'email', 'first_name', 'last_name']
That's all, since the ModelForm will take care of that.
Note that authenticate in your view is probably not necessary, since if you construct a user, it should authenticate. You can just login here:
def registration_view(request):
context = {}
context.update(csrf(request))
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
newuser = form.save()
auth.login(request, newuser)
return redirect('home')
else:
form = RegistrationForm()
context['form'] = form
return render(request, '/registration.html', context)
Try to use this in your register template
<form method="post" id="register-account-form">
{% csrf_token %}
{% for field in form %}
{% if field.help_text %}
<div class="notification error closeable">
<small style="color: grey">{{ field.help_text }}</small>
<a class="close" href="#"></a>
</div>
{% endif %}
{% for error in field.errors %}
<div class="notification error closeable">
<p style="color: red">{{ error }}</p>
<a class="close" href="#"></a>
</div>
{% endfor %}
{% endfor %}
<div class="input-with-icon-left">
<i class="icon-feather-user"></i>
{{ form.username }}
</div>
I find mistake
<div class="input-group register">
{{ form.password1.errors }}
<label for="id_password1">Пароль: </label>
{{ form.password1 }}
</div>
<div class="input-group register">
{{ form.password2.errors }}
<label for="id_password2">Подтвердите пароль: </label>
{{ form.password2 }}
</div>
Related
When I try to click on login button it always execute the invalid credentials instead of redirect to the index page.. What I did is that in database create table name signup and wants to validate all the data from that table.. Here signup_data function is works well but in login_data cannot authenticate the user.
Models.py
from django.db import models
class signup(models.Model):
username = models.CharField(max_length=10)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
email = models.EmailField()
password = models.CharField(max_length=10)
Forms.py
from django.forms import ModelForm
from . models import signup
from django import forms
class signupform(ModelForm):
username= forms.CharField(max_length=10,widget=forms.TextInput(attrs={'class':'form-control'}))
first_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=20,widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(max_length=20,widget=forms.EmailInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=10,widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = signup
fields = '__all__'
Views.py
from django.shortcuts import render,redirect
from . forms import signupform
from . models import signup
from django.contrib import messages
from django.contrib.auth import login,authenticate
def index(response):
return render(response,'login_module/index.html')
def signup_data(response):
if response.method == 'POST':
form = signupform(response.POST)
if form.is_valid():
username = form.cleaned_data['username']
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
if signup.objects.filter(username=username).exists():
# messages.add_message(response,messages.WARNING,'Username is already taken')
messages.error(response,'Username is already taken')
return redirect('signup')
elif signup.objects.filter(email=email).exists():
messages.error(response,'Email is already taken')
# messages.add_message(response,messages.WARNING,'Email is already taken')
return redirect('signup')
else:
register_instance = signup(username=username, first_name=first_name, last_name=last_name, email=email, password=password)
register_instance.save()
messages.success(response,'Registered Successfull')
return redirect('signup')
else:
form = signupform()
return render(response,'login_module/signup.html',{'form':form, 'message': messages})
def login_data(request):
form = signupform(request.POST or None)
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return redirect('index')
else:
messages.error(request,'Invalid Credentials')
return redirect('login')
else:
return render(request,'login_module/login.html',{'form':form, 'message': messages})
Login.html
{% extends 'login_module/base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12 text-center mt-50">
<h1>Login Page</h1>
</div>
</div>
<div class="row">
<div class="col-md-4 offset-md-4 ">
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group rounded-top">
{{ form.username.label_tag }} {{ form.username }}
</div>
<div class="form-group rounded-top">
{{ form.password.label_tag }} {{ form.password }}
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Login</button>
</div>
</form>
</div>
</div>
<div class="text-center mt-50">
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">
{{ message }}
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
Login Page
As far as I can tell you are creating a signup object when signing up, but when trying to login with authenticate django is looking for the generic User model. You have to create a User in the database rather than a signup object to use authenticate.
I am (attempting to) implement the ability for a user to edit and update their email address on their profile page. I am getting no errors when doing this end to end but the new email is not being saved to the DB.
Everything seems to be working, even the redirect to the profile page in the edit_profile function, but the save() doesn't seem to be working, the users email doesn't update and when I am redirected back to the profile page, the email is still the current value.
Thanks!
Model:
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
is_pro = models.BooleanField(default=False)
is_golfer = models.BooleanField(default=False)
def __str__(self):
return self.email
Form
class EditProfileForm(forms.Form):
email = forms.EmailField(
label='', widget=forms.TextInput(attrs={'class': 'form-field'}))
View
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = CustomUser.objects.get(id=request.user.id)
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
URLS
urlpatterns = [
path('type_a_signup/', ASignUpView.as_view(), name='a_signup'),
path('type_b_signup/', BSignUpView.as_view(), name='b_signup'),
path('login/', LoginView.as_view(), name='login'),
path('password_reset', PasswordResetView.as_view(), name='password_reset'),
path('typea/<username>/', typeA, name='typeA'),
path('typeb/<username>/', typeB, name='typeB'),
path('login_success/', login_success, name='login_success'),
path('edit_profile/', edit_profile, name='edit_profile'),
]
Template
<div class="container">
<div class="form-container">
<h2>Edit profile</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.email.label_tag }}
<input type="text" class="form-control {% if form.email.errors %}is-invalid{% endif %}" id="id_email"
name="email" value='{{ form.email.value|default:user.email }}'>
{% if form.email.errors %}
<div>{{ form.email.errors }}</div>
{% endif %}
</div>
<button type="submit">Submit</button>
</form>
<br>
</div>
You never set the email field of the object. You should set this with:
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = request.user
user.email = email # 🖘 set the email field
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
You should only redirect in case the form is successful. If it is not, Django will rerender the form with the errors.
I have this model:
class User(AbstractUser):
REQUIRED_FIELDS = []
USERNAME_FIELD = 'email'
email = models.EmailField(
_('email address'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters of fewer. Must be a valid email address.'),
error_messages={
'unique':_("A user with that email address already exists."),
},
)
this form class:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username','email','password']
this view class:
class UserFormView(View):
form_class = UserForm
template_name = 'workoutcal/register.html'
def get(self, request):
print("Hi again")
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)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('workoutcal:calendar')
return render(request, self.template_name, {'form': form})
and this url:
url(r'^register/$', views.UserFormView.as_view(), name='register')
So when I go to /workoutcal/register, I see this:
The "help text" is always shown in the browser. Is this default Django behaviour, or is it due to some error I have made?
Also, how do I make the text only show up if the user has entered bad data into the respective fields?
Yes if you are using {{ form }} in your template
It will always show help_text, label, errors and widget automatically
If you don't want that you need to render form manually by looping over fields
<form method="post" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{{ field.help_text }} <!-- remove this line if you don't want to show it in your html.-->
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
For more read docs: https://docs.djangoproject.com/en/2.0/topics/forms/
I don't want to display the verifications on the screen neither on username nor on password until a user fills invalid data, how can I do that ?!
Here is my user form in forms.py :
class UserForm(UserCreationForm):
class Meta():
model = User
fields = ('username','first_name','last_name','email','password1','password2',)
def save(self,commit=True):
user = super(UserForm,self).save(commit=False)
user.username = self.cleaned_data["username"]
user.email = self.cleaned_data["email"]
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
user.password1 = self.cleaned_data["password1"]
user.password2 = self.cleaned_data["password2"]
if commit:
user.save()
return user
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = 'Username'
self.fields['first_name'].label = 'First Name'
self.fields['last_name'].label = 'Last Name'
self.fields['email'].label = 'Email Address'
self.fields['password1'].label = 'Password'
self.fields['password2'].label = 'Re-enter Password'
and here is my registration function :
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password1)
user.save()
c_user = user_form.instance.id
profile = profile_form.save(commit=False)
profile_form.instance.userid = AuthUser(c_user)
profile.save()
if 'profilepic' in request.FILES:
profile.profilepic = request.FILES['profilepic']
profile.save()
registered = True
else:
print(user_form.errors)
print(profile_form.errors)
else:
user_form = UserForm
profile_form = UserProfileForm
return render(request,'registration/register.html',{'user_form':user_form,'profile_form':profile_form,'registered':registered})
My registration page
My registration template
use this template:
<div class="container">
<div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4">
<form method="post">
{% csrf_token %}
<div class="panel panel-default text-center">
<h2>Sign up!</h2>
</div>
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" class="btn btn-success">Signup!</button>
</form>
</div>
</div>
this will show errors when the user type invalid data.
How to authenticate user until he verify the email?
In my sign up process, I create the User, which means he can login even without verify email. Is there a build-in method to set a un-verified status on a User?
models.py
email_active = models.BooleanField(default=False,
verbose_name=u'Email active ')
views.py
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password)
if user is not None:
if user.email_active:
login(self.request, user)
return HttpResponse("login success")
else:
return HttpResponse("user email is not active")
else:
return HttpResponse("username or password error")
you can active email by send email with verify_code,user can use verify_code to active their email.
Demo:
models.py:
class EmailVerify(models.Model):
owner = models.ForeignKey(User,
on_delete=models.CASCADE,
verbose_name='owner')
verify_code = models.CharField(max_length=254,
null=True,
verbose_name='verify_code ')
def update(self):
self.verify_code = self.generate_key()
self.save()
return self.verify_code
def get_active_email_url(self, request):
from django.urls import reverse
url = '{}?active_code={}'.format(request.build_absolute_uri(reverse('user_login', args=())), self.verify_code)
return url
#staticmethod
def generate_key():
return binascii.hexlify(os.urandom(20)).decode()
class Meta:
verbose_name = 'EmailVerify'
utils.py :
def send_active_email(request, user):
current_site = get_current_site(request)
site_name = current_site.name
if EmailVerify.objects.filter(owner=user, category=0).exists():
verify = EmailVerify.objects.filter(owner=user).first()
else:
verify = EmailVerify.objects.create(owner=user)
verify.update()
title = u"{} active email".format(site_name)
message = "".join([
u"click this link can active your email:\n\n",
"{}\n\n".format(verify.get_active_email_url(request=request)),
])
try:
send_mail(title, message, settings.DEFAULT_FROM_EMAIL, [user.email])
message = "success"
except ConnectionRefusedError as e:
message = e.strerror
except Exception as e:
message = str(e)
return message
views.py
class LoginView(BaseContextMixin, FormView):
template_name = 'user/login.html'
form_class = LoginForm
success_url = reverse_lazy('index')
def get_context_data(self, **kwargs):
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
if 'active_email' in self.request.GET:
active_email = self.request.GET.get('active_email')
try:
user = User.objects.get(email=active_email, email_active=False)
kwargs['message'] = send_active_email(self.request, user)
except (ObjectDoesNotExist, MultipleObjectsReturned):
kwargs['message'] = 'email not exist or actived'
if 'active_code' in self.request.GET:
active_code = self.request.GET.get('active_code')
try:
email_verify = EmailVerify.objects.get(verify_code=active_code)
email_verify.owner.email_active = True
email_verify.owner.save()
email_verify.delete()
kwargs['message'] = 'email {} actived'.format(email_verify.owner.email)
except ObjectDoesNotExist:
kwargs['message'] = 'unless link'
except MultipleObjectsReturned:
EmailVerify.objects.filter(verify_code=active_code).delete()
kwargs['message'] = 'error!'
return super(LoginView, self).get_context_data(**kwargs)
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(request=self.request, **self.get_form_kwargs())
forms.py:
class LoginForm(forms.Form):
active_email = None
username = forms.CharField(label='username')
password = forms.CharField(widget=forms.PasswordInput, label='password')
def __init__(self, request, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.request = request
self.fields['username'].widget.attrs.update({'class': 'form-control',
"placeholder": self.fields['username'].label})
self.fields['password'].widget.attrs.update({'class': 'form-control',
"placeholder": self.fields['password'].label})
def clean(self):
username = self.cleaned_data["username"]
password = self.cleaned_data["password"]
user = authenticate(username=username, password=password)
if user is not None:
if user.email_active:
login(self.request, user)
else:
self.active_email = user.email
self.add_error("username", "not active")
else:
self.add_error("username", "username or password error")
login.html:
{% extends "user/user_base.html" %}
{% block content %}
<div class="login-box">
<div class="login-logo">
{{ website_title|default_if_none:'' }}
</div>
<div class="login-box-body">
<form method="post" action="{% url 'user_login' %}" class="form">
{% csrf_token %}
{% for field in form %}
<div class="form-group no-margin {% if field.errors %} has-error {% endif %}">
<label class="control-label" for="{{ field.id_for_label }}">
<b>{{ field.label }}</b>
{% if message %}
{% ifequal field.name 'username' %}{{ message }}{% endifequal %}
{% endif %}
{% if field.errors %}
{{ field.errors.as_text }}
{% ifequal field.errors.as_text '* not active' %}
<a href="{% url 'user_login' %}?active_email={{ form.active_email }}">
send active emial
</a>
{% endifequal %}
{% endif %}
</label>
{{ field }}
</div>
{% endfor %}
<div class="row">
<div class="col-md-6">
<button id="btn_login" type="submit" style="width: 100%"
class="btn btn-raised btn-primary">Login
</button>
</div>
</div>
</form>
</div>
</div>
{% endblock %}