so i have been follow Django Documentation example regarding Custom user Model (AbstractBaseUser). But when i create user from admin site it started giving me this error
"local variable 'password1' referenced before assignment"
Below i Have include admin.py
from django.contrib import admin
from django import forms
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(label= 'Password' , widget =
forms.PasswordInput)
password2 = forms.CharField(label = 'Password Confirmation', widget =
forms.PasswordInput)
class Meta:
model = CustomUser
#with my added feilds in AbstractBaseUser
fields = ('email','first_name','last_name', 'Mobile',
'Aadhar_Card', 'Address','is_supervisor','is_employee','is_driver')
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("Passwords Dont Match")
return password2
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
Your clean_password2 method is indeed referencing undefined variables. You need to use strings:
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
Related
I am using LDAP for authentication in my Django app so when adding a user in the admin page I don't need to set a password since the user will be authenticated against the LDAP backend. I'd like to modify the 'Add user' page in the admin views to have a boolean selector to identify when I am trying to add an LDAP user so that the password field is not required. I'd like to retain the option of supplying a password in case I need to add a local user that authenticates against Django's backend.
Here is what I've cobbled together so far:
models.py
Modified the save method so that the user gets populated in the CustomUser model if isLdap is True.
class CustomUser(AbstractUser):
pass
isLdap = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if self.isLdap:
user = LDAPBackend().populate_user(self.username)
else:
super().save(*args, **kwargs)
def __str__(self):
return self.username
admin.py
I successfully added a check box to identify if the new user is an LDAP user but the value isn't being saved to the CustomUser model and I need to change save_model so it saves the actual password if it is valid otherwise set_unusable_password().
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
add_fieldsets = (
(None, {
'description': (
"Enable 'IsLdap' if the username is a LAN ID. "
),
'fields': ('username','isLdap'),
}),
('Password', {
'fields': ('password1', 'password2'),
}),
)
model = CustomUser
def save_model(self, request, obj, form, change):
obj.set_unusable_password()
super(UserAdmin, self).save_model(request, obj, form, change)
admin.site.register(CustomUser, CustomUserAdmin)
forms.py
Not sure if this is the spot or how to do it, but I think here is where I need to conditionally set ....required = False if isLdap is True.
class CustomUserCreationForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
self.fields['password1'].required = False
self.fields['password2'].required = False
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("Passwords don't match")
return password2
Appreciate any help in getting this code functional!
Here's what I ended up doing:
Models.py
from django.db import models
from django.contrib.auth.models import (AbstractUser, BaseUserManager, )
from django_auth_ldap.backend import LDAPBackend
from django.dispatch import receiver
# Create your models here.
class CustomUserManager(BaseUserManager):
def create_user(self, username, is_ldap, password, **extra_fields):
if not username:
raise ValueError(_('The username must be set'))
user = self.model(username=username,
is_ldap=is_ldap,
**extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, username, is_ldap, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(username, is_ldap, password, **extra_fields)
class CustomUser(AbstractUser):
is_ldap = models.BooleanField(default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['is_ldap']
objects = CustomUserManager()
def __str__(self):
return self.username
#receiver(models.signals.post_save, sender=CustomUser)
def user_created(sender, instance, created, **kwargs):
if created and instance.is_ldap:
user = LDAPBackend().populate_user(instance.username)
admin.py
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError
from .models import CustomUser
class CustomUserCreationForm(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)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password1'].required = False
self.fields['password2'].required = False
class Meta:
model = CustomUser
fields = ('username','is_ldap',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
is_ldap = self.cleaned_data.get("is_ldap")
if is_ldap:
if password1 or password2:
raise ValidationError("Leave password fields empty for an LDAP user")
else:
if not password1 or not password2:
raise ValidationError("Passwords don't match")
elif password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
if self.cleaned_data['is_ldap']:
user.set_unusable_password()
else:
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class CustomUserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
disabled password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = CustomUser
fields = ('username','is_ldap',)
class CustomUserAdmin(UserAdmin):
# The forms to add and change user instances
form = CustomUserChangeForm
add_form = CustomUserCreationForm
model = CustomUser
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('username', 'first_name', 'last_name', 'is_staff', 'is_active', 'is_ldap',)
# list_filter = ('username', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('username', 'is_ldap', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name')}),
('Permissions', {'fields': ('is_superuser','groups')}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'is_ldap', 'password1', 'password2'),
}),
)
search_fields = ('username',)
ordering = ('username',)
filter_horizontal = (['groups',])
admin.site.register(CustomUser, CustomUserAdmin)
I am working with AbstractBase user. I have created users and groups. After I assign group to user, if I login with that user , the user has access to the complete admin site with all the CRUD operations.
I have a created a product group with add-delete-edit-view permissions(default) and assigned a user to it. But when this user logins to the admin site, he has access to all the other items of the site as well.
How do I make sure the logged in user can access only the items from assigned groups /permissions???
#managers.py
from django.contrib.auth.base_user import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_active', True)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
#models.py
from __future__ import unicode_literals
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from .managers import UserManager
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
is_superuser = models.BooleanField(_('is_superuser'), default=True)
is_staff= models.BooleanField(_('is_staff'), default=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
'''
Returns the first_name plus the last_name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Returns the short name for the user.
'''
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
'''
Sends an email to this User.
'''
send_mail(subject, message, from_email, [self.email], **kwargs)
#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)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
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
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)
class Meta:
model = User
fields = ('email',)
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 = ('email', 'password', 'is_active','is_superuser','is_staff')
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"]
#admin.py
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserAdminCreationForm, UserAdminChangeForm
from .models import User
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'is_superuser')
list_filter = ('is_superuser',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ()}),
('Permissions', {'fields': ('is_superuser','groups')}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
typo : password instead of password1
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
and you are also missing this methods in you User Model:
def has_perm(self, perm, obj=None):
return True # self.is_admin
def has_module_perms(self, app_label):
return True
I want to have a user sign up form in Django, I know that for the Backend I should have something like this:
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon#thebeatles.com', 'johnpassword')
>>> user.last_name = 'Lennon'
>>> user.save()
However, I don't know how to make the Frontend. I've already looked up in the Django documentation and found the UserCreationForm class and it says it's deprecated.
What should I do? Thank you
Try something like this:
#forms.py
class UserCreationForm(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)
class Meta:
model = MyUser
fields = ('email', 'date_of_birth')
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 ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
You should read this section of the Django Docs on authentication.
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
Im learning django and im trying to understand the registration progress with an UserCreationForm and a CreateView, I want to use an email as field on the registration form but they keep poping an error about KeyError 'email' on my form.
forms.py
from django import forms
from accountApp.models import Profile
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username','first_name', 'last_name', 'email')
class CreateUserForm(UserCreationForm):
fields = ('username', 'email', 'password1', 'password2')
model = get_user_model()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].label = 'Usuario'
self.fields['email'].label = 'Email'
views.py
from django.urls import reverse, reverse_lazy
from . import forms
class RegistrationPage(CreateView):
template_name = 'accountApp/register.html'
success_url = reverse_lazy('accApp:profilepage')
form_class = forms.CreateUserForm
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
def __str__(self):
return self.user.username
IMG 01 error
IMG 02 error
It is failing here
self.fields['email'].label = 'Email'
Here you can see that UserCreationForm form you are inheriting from has no field email.
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,
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput,
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.update({'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 forms.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 forms.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
You can add fields if you want to
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
and override save method.