django custom Registration Form which inherits from "UserCreationForm" - django

I have a small question about Django so I have a custom Registration Form which inherits from "UserCreationForm" and therefore I use "fields" to define the fields I want to display. For this test just ("username", "email",). But when I go to see my form which is displayed "Password" and "Password confirmation" are also present. Wanting to understand, I therefore went to see the UserCreationForm class of django but this one has a Meta class which has fields = ("username"), so I don't really see why I have the passwords which are also present. I'm sorry the explanation is a bit laborious but I would like to understand so if anyone has a little explanation thank you very much.
My custom class:
class CustomSignupForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ("username", "email",)
The UserCreationForm of django:
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"),
strip=False,
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
strip=False,
help_text=_("Enter the same password as before, for verification."),
)
class Meta:
model = User
fields = ("username",)
field_classes = {"username": UsernameField}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self._meta.model.USERNAME_FIELD in self.fields:
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs[
"autofocus"
] = True
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError(
self.error_messages["password_mismatch"],
code="password_mismatch",
)
return password2
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 ValidationError as error:
self.add_error("password2", error)
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
Here is what it gives:
Display of my form

The reason this happens is that the password1 and password2 field are defined in the UserCreationForm class. The form fields do not need to be listed in the fields attribute: all field objects in the class are form fields.
A ModelForm will in essence add form field objects to the class, and thus automates that process, but any field object defined in the class is a form field, that is how a simple Form [Django-doc] behaves, and a ModelForm is just a subclass of Form.
Based on your comment you want to reorder the fields. You can do so with the .field_order attribute [Django-doc]:
class CustomSignupForm(UserCreationForm):
field_order = ('username', 'email', 'password1', 'password2', 'newsletter')
class Meta:
model = CustomUser
fields = ('username', 'email', 'newsletter')

Related

How to add Choice Field to Django forms for user registration?

I am making a registration form for 3 types of users. When a user enters email and password he/she must select one of the roles.
First I used BooleanFields and it works, but more than one checkbox can be selected. I need that user can select only one role.
I have tried ChoiceField, which I could display on the template but it does not POST any data to db.
forms.py
class RegisterForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
parent = forms.BooleanField(label="I am a Parent")
school = forms.BooleanField(label="I am a School Admin")
vendor = forms.BooleanField(label="I am a Vendor")
role_select=forms.ChoiceField(
widget=forms.RadioSelect,
label="Select your role.",
choices=(('is_parent','parent '),('is_school','school'),('is_vendor','vendor')),
)
if not parent and not school and not vendor:
raise forms.ValidationError("Users must have a role")
class Meta:
model = User
fields = ['role_select', 'parent', 'school', 'vendor', 'email'] #'full_name',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.role_select( self.cleaned_data['role_select'])
# user.active = False # send confirmation email
if commit:
user.save()
return user
As you see in the forms.py I have a combination of two approaches. So it has some useless lines. Which approach to use and how?
you can use Django groups where you can create a group and assign it as a choicefield when user registers. You can check my repository. I have done the same thing here. Hope it can get you some idea
https://github.com/tsephel/User-authentication-django-/tree/master/env

How do you call the default add user form for a custom admin

I created a customized User Admin change form but when I create a new user it goes to the Change form.
The Base Admin add form meets what I want hence why I want to keep it?
Also how do I encrypt the password once I reverted back to the Base admin create form?
How do I change this?
Admin.py:
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserAdminChangeForm
from .models import User
# Register your models here.
User=get_user_model()
class UserAdmin(admin.ModelAdmin):
form = UserAdminChangeForm
search_fields=['username','user_type']
list_display=('username','full_name','password','email','user_type','ad','pqa','ts','tl','tm','stm','active')
list_filter = ('ad',)
fieldsets = (
(None, {'fields': ('username', 'password')}),
('Personal info', {'fields': ('full_name','birth_date','hire_date',)}),
('Permissions', {'fields': ('ad','tm','pqa','stm','ts','tl')}),
)
class Meta:
model = User
admin.site.register(User,UserAdmin)
forms.py:
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
usertype= forms.Select(choices=User.USER_TYPE_CHOICES)
class Meta:
model = User
fields = ('username',)
def clean_username(self):
username = self.cleaned_data.get('username')
qs = User.objects.filter(username=username)
if qs.exists():
raise forms.ValidationError("Username is taken")
return username
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit = True):
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
usertype= forms.Select(choices=User.USER_TYPE_CHOICES)
class Meta:
model = User
fields = ['username','password','user_type']
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('username', 'password', 'active', 'ad')
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"]
I really appreciate the help. TIA

Update custom user password using UpdateWithInlinesView from django-extra-views app

I have a model 'Admin' related to a (custom) user within a one to one field. To update all the fields I'm using django-extra-views app that basically use Django formset. It works well but for updating the password.
Models
class Users(AbstractUser):
# common fields for all the users
class Admins(models.Model):
# Custom fields for the admins
Forms:
class AdminProfileForm(forms.ModelForm):
class Meta:
model = Users
fields = ['first_name', 'last_name']
password1 = forms.CharField(widget=forms.PasswordInput, label='New Password')
password2 = forms.CharField(widget=forms.PasswordInput, label='Confirm Password')
Views:
class AdminInline(InlineFormSet):
model = Admins
fields = ['admins_fiels_here']
class AdminProfile(BaseContext, UpdateWithInlinesView):
....
inlines = [AdminInline]
form_class = AdminProfileForm
def get_object(self):
return Users.objects.get(pk=self.request.user.id)
def forms_valid(self, formset, inlines):
password1 = formset.cleaned_data['password1']
password2 = formset.cleaned_data['password2']
if password2 and password1:
if password1 != password2:
# raise a ValidationError message
user = self.request.user # at this point password is 'old_passord'
user.set_password(password1) # now is 'password1'
user.save() # 'password1' is correctly saved in db
return super(AdminProfile, self).forms_valid(formset, inlines)
As I describe above, the new password is saved but when super(AdminProfile, self).forms_valid(formset, inlines) ends its works the password results to be the old one.

ModelForm not finding field when submitting

I currently have this ModelForm for validating a new user registration:
class RegistrationForm(forms.ModelForm):
email = forms.CharField(max_length=75, required=True)
password = forms.PasswordInput()
password_confirm = forms.PasswordInput()
class Meta:
model = User
fields = ['username', 'email', 'password']
def clean(self):
if self.password != self.password_confirm:
self.add_error('password_confirm', 'Passwords do not match.')
The user is required to confirm his password. When submitting this form I get the following error:
ValueError at /register
'RegistrationForm' has no field named 'password_confirm'.
I tried using the self.cleaned_data as well, but still get the same error.
The fields attribute cannot be removed nor can password_confirm be added to it.
How would one go about fixing this?
password and password_confirm are defined as widgets, not form fields.
Define two CharFields and pass the widget argument:
class RegistrationForm(forms.ModelForm):
email = forms.CharField(max_length=75, required=True)
password = forms.CharField(widget=forms.PasswordInput)
password_confirm = forms.CharField(widget=forms.PasswordInput)
You need to call the super clean first, and then you should use the cleaned data rather than the field.
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
if cleaned_data.get('password') != cleaned_data.get('password_confirm'):
self.add_error('password_confirm', 'Passwords do not match.')

Field validation in a Django form

I have a Django form consisting of a email and name field. I want to validate the name to have more than 8 characters. I have used the following code. But it is not working.
class SignUpForm(forms.ModelForm):
class Meta:
model=SignUp
fields=('email','name')
def emailValidation(self):
name=self.cleaned_data.get('name')
if len(name) <=8:
raise forms.ValidationError("name cannot be less than 8")
models.py
class SignUp(models.Model):
name=models.CharField(max_length=200)
email=models.EmailField()
timestamp=models.DateTimeField(auto_now_add=True, auto_now=False)
updated=models.DateTimeField(auto_now=True,auto_now_add=False)
def __unicode__(self):
return self.name
views.py
def home(request):
form=SignUpForm(request.POST or None)
if form.is_valid():
instance=form.save(commit=False)
instance.save()
print instance.timestamp
return render(request, 'home.html',{'form':form})
In your SignUpForm, in the function emailValidation, you haven't returned 'name'. Also a major mistake is that you have to name the function clean_(field_name) and NOT emailValidation.
This should do it I guess:
class SignUpForm(forms.ModelForm):
class Meta:
model=SignUp
fields=('email','name')
def clean_name(self):
name=self.cleaned_data.get('name')
if len(name) <=8:
raise forms.ValidationError("name cannot be less than 8")
return name
You need to use correct name for your validation method. Django forms will call methods with the format clean_<fieldname>.
Also you seem to be confused about which field you are validating; your email validation method should be called clean_email and should access the email value via form.cleaned_data['email'], and the name one should be called clean_name and access form.cleaned_data['name'].
Something like this may give you some guidance.
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
firstname = forms.CharField(label="First Name")
lastname = forms.CharField(label="Last Name")
phone = forms.CharField(label="Phone")
email = forms.EmailField(label="Email")
password1 = forms.CharField(label="Password")
password2 = forms.CharField(label="Password (again)")
min_password_length = 8
class Meta:
model = User
fields = ['firstname', 'lastname', 'phone', 'email', 'password1', 'password2']
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError(u'Email "%s" is already in use! Please log in or use another email!' % email)
return email
def clean_password1(self):
" Minimum length "
password1 = self.cleaned_data.get('password1', '')
if len(password1) < self.min_password_length:
raise forms.ValidationError("Password must have at least %i characters" % self.min_password_length)
else:
return password1
def clean(self):
"""
Verifies that the values entered into the password fields match
NOTE: Errors here will appear in ``non_field_errors()`` because it applies to more than one field.
"""
cleaned_data = super(RegistrationForm, self).clean()
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords didn't match. Please try again.")
return self.cleaned_data
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user