'Create an account from django-admin
In my CRM, the owner of the company gives the first password and email for new employees. Employee can change them later (I don't need to show them in admin, which is not allowed by django by default). But how to show the fields for giving the first password in admin? For examplle fields - "Password for new user" and "Again password for new user"
models.py
class CustomUser(AbstractUser):
[...]
def __str__(self):
return self.email
admin.py
from django.contrib import admin
from .models import CustomUser
admin.site.register(CustomUser)
I need this effect:
Solution 1:[1]
When dealing when custom user models it's important to ensure that the forms used account for this password validation. You have two options to achieve that:
- As your
CustomUserclass inherits fromAbstractUser, you can make use of the forms that Django provides us to handle our user instances:
# forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields + ('email',)
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = CustomUser
fields = UserChangeForm.Meta.fields # Includes all fields by default, no need to specify email
By looking at the docs we see that our CustomUserCreationForm will contain 4 fields (username, email, password1 and password2). CustomUserChangeForm will contain all fields in the CustomUser model but it will mask the password field so it won't be editable from the form itself. You can take a look at the source code for UserCreationForm and UserChangeForm to see how Django handles this forms. If the fields used don't suit your needs, I would go with the second approach that I will explain later where you will be able to customize your forms further.
Now we have to specify that we want to use those forms while editing our CustomUser instances in the admin:
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import CustomUser
from .forms import CustomUserCreationForm, CustomUserChangeForm
@admin.register(CustomUser)
class CustomUserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = CustomUserChangeForm
add_form = CustomUserCreationForm
fieldsets = BaseUserAdmin.fieldsets
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = BaseUserAdmin.add_fieldsets + (
(None, {'fields': ('email',)}),
)
If we want to customize it better, we can go with the second option.
- Create our forms almost from scratch to handle
CustomUserinstances. The process is the same as before, but the way to specify the forms and register them to the admin is different:
# forms.py
from django import forms
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)
class Meta:
model = CustomUser
fields = ('email', 'is_superuser')
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
class CustomUserChangeForm(forms.ModelForm):
"""A form for updating users. Include 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 = ('email', 'password', 'is_superuser')
Keep in mind that the fields attribute is used to control which fields in your model need to be included in the corresponding forms, I just added email and is_superuser as examples but you should use the ones you need. Usually creation forms display only the necessary fields to create instances and update forms contain all editable fields in your model (in this case I would add more fields to CustomUserChangeForm but as I don't have much info about CustomUser I just added some fields I know the model has).
With that into account, now we have to specify to that we want to use these forms in our admin panel, just the same way we did before but changing fieldsets and add_fieldsets:
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import CustomUser
from .forms import CustomUserCreationForm, CustomUserChangeForm
@admin.register(CustomUser)
class CustomUserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = CustomUserChangeForm
add_form = CustomUserCreationForm
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_superuser',)}),
)
# 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', 'is_superuser', 'password1', 'password2'),
}),
)
You can read about Customizing authentication in Django if you need more context on this
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | mtzd |

