I'm trying to secure that each email can only be used once, thus having the following clean method
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
.
.
.
def clean_email(self):
"""
Check if that email already exists in the database
"""
email = self.cleaned_data["email"]
if User.objects.filter(email=email).exists():
raise ValidationError("This email already exists")
return email
and all the checks works as intended. The issue is that after the user is created, the email field is empty. Even if I hardcode the returned-email i.e
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
.
.
.
def clean_email(self):
email = self.cleaned_data["email"]
if User.objects.filter(email=email).exists():
raise ValidationError("Der er allerede en bruger med den email")
return "my_email#email.com"
it is still empty in the database when the user is created.
I have attached the view aswell below, if that could be it
#views.py
def register(request):
if request.method=="POST": #post request
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Yey - success! Log in here ")
return redirect("login")
else:
form = UserRegisterForm()
return render(request,"users/register.html",context= {"form":form})
What am I missing here?
UserCreationForm from django.contrib.auth doesn't have a facility to save additional fields. It only handles the username (more precisely the field defined as USERNAME_FIELD on the model returned by get_user_model()) and the password.
You need to do the following in your view:
...
if form.is_valid():
user = form.save(commit=False)
user.email = form.cleaned_data["email"]
user.save()
messages.success(request, "Yey - success! Log in here ")
return redirect("login")
Related
I have created a registration form using the class models.User (refer) in Django as follows:
from Django.shortcuts import render, redirect
from django.contrib.auth.models import User
def register(request):
if request.method == 'POST':
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
confirm_password = request.POST['confirm_password']
if password == confirm_password:
# some code
user = User.objects.create_user(username=username, email=email, password=password)
user.save()
return redirect('login')
else:
return redirect('register')
return render(request, 'register.html')
My problems:
Now I want to make Full Name as optional but all other fields as required, also I want to apply length constraint on my fields, how can I do that? As this is an inbuilt model (class models.User), I am not sure how to set blank=True or use max_length for any field.
Also I want to remove the spaces (if any) at the end and beginning of the entered data, before saving it using user.save() (e.g. if someone entered the name as " abc efg " I want to save it as "abc efg"). Basically, I want to use .is_valid() feature of the Django forms. I even tried doing that as:
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
def register(request):
if request.method == 'POST':
form = User(request.POST or None)
if form.is_valid():
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
confirm_password = request.POST['confirm_password']
if password == confirm_password:
# some code
user = User.objects.create_user(username=username, email=email, password=password)
user.save()
return redirect('login')
else:
return redirect('register')
else:
return redirect('register')
return render(request, 'register.html')
but this is giving me the following error: 'User' object has no attribute 'is_valid'
Any ideas about how can I make the fields optional/required and set the max_length of the fields & remove the trailing spaces (if any) all while using the inbuilt model class models.User?
You need to declare a form first. If you are using default django user, then you can user UserCreationForm to validate the data:
from django.contrib.auth.forms import UserCreationForm
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST or None)
if form.is_valid():
form.save()
# rest of the code
Now, lets say you want want to clean the data which you get from the HTML form, then you can use clean_<field_name> method. To do that inside UserCreationForm, you can override it(also adding some code to show how to customize forms):
class CustomUserForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
def clean_first_name(self):
return self.cleaned_data['first_name'].strip()
Please see the documentation for more information on validation and cleaning data in forms.
As per the django docs, it is best to create your own user model by inheriting from the AbstractBaseUser: https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#specifying-a-custom-user-model
There you can define what's optional and what not.
Oh, and while you're at it - maybe it's also worth looking at django-allauth. Maybe not too relevant right now but for sure down the road! Also check out the custom forms.
I'm working on a simple login and logout app in Django.
I wrote two views one for login and another for register.
Register view is working as expected. But login view is causing issues.
I'm using form.is_valid() in login view. That is where the issue is arising. If I print the form in else block, it is saying A user with that username already exists. This is happening even before trying to authenticate the user. Some one help me with this.
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.http.response import HttpResponse
from django.shortcuts import render
from notes.forms import UserForm
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
elif request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user:
login(request, user)
return HttpResponse("Logged in")
else:
return HttpResponse("Wrong creds")
else:
print(form)
return HttpResponse("else of is_valid()")
def register(request):
if request.method == 'GET':
return render(request, 'register.html')
elif request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
email = form.cleaned_data['email']
existing = User.objects.filter(username=username)
if existing:
return HttpResponse('Username is already taken')
else:
User.objects.create(username=username, password = password, email=email)
return HttpResponse("User created with "+ username +" username")
else:
return HttpResponse("Hi")
forms.py
from django.contrib.auth.models import User
from notes.models import Note
from django import forms
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = '__all__'
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'email', 'password']
The form.is_valid() call will validate the form, this is done through several steps. Depending on the fields of the model, it thus also checks the uniqness of the data.
The User [Django-doc] model has a uniqness constraint on the username, hence the UserForm can only be valid, if the username is not yet taken, or when the form contains a instance that is already stored in the database.
I therefore think that it might be better to create a LoginForm, like Django does with an AuthenticationForm [Django-doc] [GitHub]. For example:
class UserForm(forms.Form):
username = forms.CharField()
password = forms.CharField()
I understand that django comes with a User model built in and the following code works and properly saves a user to the db, I just don't understand why it works:
from django.shortcuts import render
from django.http import HttpResponse
from .forms import UserCreationForm
def index(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
return HttpResponse('Saved')
else:
form = UserCreationForm()
return render(request, 'core/index.html', {'form':form})
what is the line form = UserCreationForm(request.POST) saying? is the (request.POST) the contents of the submitted form? and how does user = form.save() save a user to the database? I was thinking that maybe the variable had to be named user for django to recognize it as a User object but this is not the case as I changed the statement to test = form.save()
and it still saved a User to my database.
The line form = UserCreationForm(request.POST) talks of itself actually. It posts data passed through your form to the variable form
The 'request' object is an HttpRequest object that carries metadata about the request (for example in our case, we have a post request , and the request object carries the user data). Check this for more details.
Yes, user = form.save() saves a User instance in the database. UserCreationForm has a function called save() and here we're just calling that function.
The name of the variable has nothing to do with it because in the UserCreationForm's definition, the model is already defined as User. So, it already recognizes that it's the User model.
I this you should read the UserCreationForm code to make things clear in your head.
This is django doc :
[docs]class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
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_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()
return user
You can see the "save" method, it use user model with super. Result UserCreationForm use User model and can save in User database
Good day, I have the following two questions:
1) I'm using a custom login as shown on the django docs, but however I'm receiving an error when trying to save a new user.
This is my forms.py:
class UserCreationForm(forms.ModelForm):
"""
A form for creating a user, with no privileges.
Includes all the required fields, plus a repeated password.
"""
password1 = forms.CharField(label=_("Mot de passe"), widget=forms.PasswordInput)
password2 = forms.CharField(
label=_("Confirmer le mote de passe"),
widget=forms.PasswordInput,
help_text=_("Les deux mots de passe, doivent etre identique."))
class Meta:
model = IfasicUser
fields = ("email",)
def clean_email(self):
email = self.cleaned_data.get('email')
email_base, provider = email.split("#")
domain, extension = provider.split(".")
if not domain == "ifasic":
raise forms.ValidationError("domain doesn't exist")
if not extension == "cd":
raise forms.ValidationError("Utilisateur non identifie, reessayer.")
return 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("Les deux mots de passe, doivent etre identiques.")
return self.clean_password2
# TODO: make sure a student email must contains a student number as part of it.
# def validate_email(email):
# if '#' not in email:
# raise ValidationError('Invalid email. # not found')
# if '.' not in email:
# raise ValidationError('Invalid email. Incorrect domain?')
#
# # lowercase domain
# name, domain = email.split('#')
# email = '#'.join([name, domain.lower()])
# return email
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""
A form for updating a user. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_("Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using this form."))
class Meta:
model = IfasicUser
fields = '__all__'
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class MyAuthenticationForm(AuthenticationForm):
"""
A custom authentication form that extends the base AuthenticationForm
and overrides the username field to set it to an EmailField.
"""
username = forms.EmailField()
2) I would like to redirect a user to his content manager systems depending on the flag is_staff.
This is my attempted code. but with no results:
class AdminLogin(generic.TemplateView):
model = models.Staff
template_name = 'registration/login.html'
#sensitive_post_parameters()
#csrf_protect
#never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.POST.get(redirect_field_name,
request.GET.get(redirect_field_name, ''))
if request.method == "POST":
form = authentication_form(request, data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
# here where to redirect the user
if request.user is not None:
if request.user.is_active and request.user.is_staff:
redirect_to = 'home'
print(u'the request request.user')
# if Student.filter(user=request.user).exists():
# ...
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
Any help will be appreciated.
1) The KeyError is for password as you are using password1 and password2. One solution would be to make the fields password and then password_confirm. This happens because you are using the ModelForm, so you a password field in IfasicUseralready.
2) Right after you set the redirect_to for the user you have another if statement that might be getting triggered and overwriting the redirect_to value. So in this case, if the user is_staff and also a student, then they would redirect to wherever the students go after login.
I wanted to insert the user details in auth_user table, but it gives the error of create_user() got an unexpected keyword argument 'first_name'
forms.py
from django import forms
from django.contrib.auth.models import User
from django.forms import ModelForm
from customer_reg.models import Customer
class Registration_Form(ModelForm):
first_name = forms.CharField(label=(u'First Name'))
last_name = forms.CharField(label=(u'Last Name'))
username = forms.CharField(label=(u'User Name'))
email = forms.EmailField(label=(u'Email Address'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model=Customer
exclude=('user',)
def clean_username(self):
username=self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError("The Username is already taken, please try another.")
def clean_password(self):
password=self.cleaned_data['password']
return password
views.py
from django.contrib.auth.models import User
from customer_reg.models import Customer
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from customer_reg.forms import Registration_Form
def CustomerRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/customer_profile/')
if request.method == 'POST':
form = Registration_Form(request.POST)
if form.is_valid():
user=User.objects.create_user(first_name=form.cleaned_data['first_name'], last_name=form.cleaned_data['last_name'], username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
user.save()
customer=user.get_profile()
customer.birthday=form.cleaned_data['birthday']
customer.website=form.cleaned_data['website']
customer.store=form.cleaned_data['store']
customer.welcomemail=form.cleaned_data['welcomemail']
customer.save()
return HttpResponseRedirect('/customer_profile/')
else:
return render_to_response('customer_register.html',{'form':form} , context_instance=RequestContext(request))
else:
''' user is not submitting the form, show them a blank registration form '''
form = Registration_Form()
context={'form':form}
return render_to_response('customer_register.html',context , context_instance=RequestContext(request))
If I edit the views.py as
user=User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
then it works successfully
I have already tried firstname as well as first_name
any idea where I have done the mistake
The create_user manager method only accepts three arguments, username, email (optional), and password (optional).
Once you have created a user, you can modify the other fields, then save again.
user=User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
user.first_name = form.cleaned_data['first_name']
user.last_name = form.cleaned_data['last_name']
user.save()
If you want to be able to register using admin interface you gonna have to change the admin.py inside your app