I'm following a tutorial on making a custom User for authentication purposes. The tutorial used a certain property add_fieldsets within UserAdmin. What does this mean? I can't seem to find any documentation on this.
Here is the snippet:
class UserAdmin(UserAdmin):
"""Define admin model for custom User model with no email field."""
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name')}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
('Important dates', {'fields': ('last_login', 'date_joined')}),
('Contact info', {'fields': ('contact_no',)}),)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),}),)
list_display = ('email', 'first_name', 'last_name', 'is_staff')
search_fields = ('email', 'first_name', 'last_name')
ordering = ('email',)
Here is the tutorial I was following: How to use email as username for Django authentication (removing the username)
The add_fieldsets class variable is used to define the fields that will be displayed on the create user page.
Unfortunately it's not well documented, and the closest thing I found to documentation was a comment in the code example on https://docs.djangoproject.com/en/2.1/topics/auth/customizing/ (search page for add_fieldsets).
The classes key sets any custom CSS classes we want to apply to the form section.
The fields key sets the fields you wish to display in your form.
In your example, the create page will allow you to set an email, password1 and password2.
The add_fieldsets field works similar to fieldsets field and allows to control the layout of the admin pages but specifically the create object page whereas fieldsets field is used to control change object page.
And using add_fieldsets field you can decide which all fields should be displayed on the create object page, add description ,etc.
In your example it will create a section with no name (as set to None), set a specific width to all the fields by using classes key set and display fields email,password1 and password2
by using key set fields
I hope I cleared your doubt!!
use the BaseUserAdmin class, it enables some functionalities like add_form and add_fieldsets
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
class UserAdmin(BaseUserAdmin):
"""Define admin model for custom User model with no email field."""
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name')}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
('Important dates', {'fields': ('last_login', 'date_joined')}),
('Contact info', {'fields': ('contact_no',)}),)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),}),)
list_display = ('email', 'first_name', 'last_name', 'is_staff')
search_fields = ('email', 'first_name', 'last_name')
ordering = ('email',)
From the Django documentation (see the Note):
If you are using a custom ModelAdmin which is a subclass of django.contrib.auth.admin.UserAdmin, then you need to add your custom fields to fieldsets (for fields to be used in editing users) and to add_fieldsets (for fields to be used when creating a user).
So it's basically the same as fieldsets, but for creating users and only needed when you're extending UserAdmin. The only difference between fieldsets and add_fieldsets is that you have to treat password fields a little different ("password1" and "password2", instead of "password").
The documentation offers a full example of implementing a custom user here: https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#custom-users-admin-full-example
Related
I am trying to display the password in the Admin backend table in the following way, containing the algorithm, iterations, salt and hash:
However, my current page looks like the following:
As you can see it is just the hashed password, not displaying any of the information unlike the above. Can anyone see where I am going wrong?
Please find my code below:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from hobbies.models import extendedUser, User, Hobby
from .forms import LoginForm, SignUpForm
from django.forms import ModelForm
from django.contrib.auth.forms import ReadOnlyPasswordHashField
#admin.site.register(User,UserAdmin)
class CustomUserAdmin(UserAdmin):
add_form = SignUpForm
form = LoginForm
model = extendedUser
readonly_fields = ["password"]
list_display = ('email', 'is_staff', 'is_active',)
list_filter = ('email', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'password', 'city')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(User, CustomUserAdmin)
Thank you for your time,
Alex
I think they use display using this function:
get_session_auth_hash() which is a part of the base abstract user in django.contrib.auth.base_user
In my django app I have modified the User entity to include a worker field (OneToOneField). But from the django admin site that field yiels so many result , so it is difficult for the logged user to select a worker. Is there any way to use the select2 (ModelSelect2Widget) widgets from the django admin site?
For any regular form I have define the widgets in the following way:
from django_select2.forms import ModelSelect2Widget
class ProcessForm(forms.ModelForm):
class Meta:
model = ProcessModel
exclude = ('id',)
widgets = {
'name':forms.TextInput(attrs={'class': 'form-control'}),
'code':forms.TextInput(attrs={'class': 'form-control'}),
'description':forms.Textarea(attrs={'class': 'form-control'}),
'geom': LeafletWidget(),
'product': ModelSelect2Widget(model=ProductModel, queryset=ProductModel.objects.filter(),
search_fields=['name__icontains'],
attrs={'style': 'width: 100%;'}),
}
Is there any way to use the ModelSelect2Widget for the worker field in the admin site form?
Here is my code:
class User(AbstractUser):
worker = models.OneToOneField(WorkerModel, on_delete=models.CASCADE,
related_name="user", verbose_name=_("Trabajador"), null=True, blank=True)
class Meta:
default_permissions = ()
verbose_name="Usuario"
verbose_name_plural="Usuarios"
permissions = (
("secretario", "Secretario(a)"),
("director", "Director"),
)
from django.contrib.auth.admin import UserAdmin
class UserAdminInherited(UserAdmin):
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Worker info'), {'fields': ('worker',)}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
admin.site.register(User, UserAdminInherited)
Since Django 2.0., we can use autocomplete_fields.
autocomplete_fields is a list of ForeignKey and/or ManyToManyField
fields you would like to change to Select2 autocomplete inputs.
ModelAdmin(is parent of UserAdmin) has the property autocomplete_fields (Django Docs):
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth import get_user_model
User = get_user_model()
class UserAdminInherited(UserAdmin):
autocomplete_fields = ['worker']
...
admin.site.register(User, UserAdminInherited)
You must define search_fields on the related object’s ModelAdmin
because the autocomplete search uses it.
from django.contrib import admin
#admin.register(WorkerModel)
class WorkerModelAdmin(admin.ModelAdmin):
search_fields = ['model_field']
The problem:
I would like to use django admin site User model to register new users. The default option offers you to register new username with password and password confirmation, which are required fields.
My idea is to make few changes. I would like to keep username field and add email-field, however delete password and password confirmation. The principal idea is, I would register a user and he would receive an email with generated password. He would then be able to login with generated password and change the password.
I am facing huge problems with templates, errors and most of all overriding the classes.
I have spent many many hours checking django documentation, goolge and the best I could do so far is:
admin.py
from django.contrib import admin
from django.contrib.auth import admin as upstream
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import Group, User
from django.utils.translation import ugettext, ugettext_lazy as _
class UserAdmin(upstream.UserAdmin):
fieldsets = (
(None, {'fields': ('username', 'password','email')}),
(_('Personal info'), {'fields': ('first_name', 'last_name')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username','email')}
),
)
form = UserChangeForm
add_form = UserCreationForm
try:
admin.site.unregister(User)
except NotRegistered:
pass
admin.site.register(User, UserAdmin)
This is a code I have found on stackoverflow. Within add_fieldsets I removed password1, and password2. If I go to admin page, everything looks great, however I can not register a user.
I think it is because of UserCreationForm, which insists of creating an password, but perhaps I could be wrong. Can anyone please let me know how to override UsercreationForm, so passwords wouldn't be mandatory anymore and errors from UserCreationForm would not be seen on the site.
Customizing Django auth can be very difficult and that's why I would recommend looking into 3rd party apps to help you achieve your goals. One you might want to check out is: https://github.com/bee-keeper/django-invitations
even though it is an old question and no real answer, one way to do most of the stuff (without knowing how to act on the "send password") would be:
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.auth.forms import UserCreationForm as DjangoUserCreationForm
class UserCreationForm(DjangoUserCreationForm):
password1 = None
password2 = None
def clean(self):
password = get_random_string() # here you want to maybe send a signal which can be picked up or something
self.cleaned_data['password1'] = password
self.cleaned_data['password2'] = password
return super().clean()
class UserAdmin(DjangoUserAdmin):
add_form = UserCreationForm
fieldsets = (
(None, {'fields': ('username',)}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email'),
}),
)
list_filter = tuple()
list_display = ('username', 'email', 'first_name', 'last_name')
admin.site.register(User, UserAdmin)
I want to add my settings.AUTH_USER_MODEL to my admin insted of User model.
I register it with the snippet I found in the docs:
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# 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', 'bdate')
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('bdate', 'website', 'location')}),
)
# 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 = ()
In fieldsets Personal info I added all my custom info. Now I also want to display all inherited fields like first_name, username, etc. I can add them one by one to fieldsets, but I am not sure if that's the right way.
Is there a way just to inherit them from User model without specifying explicitly?
You could make use of ModelAdmin.get_fieldsets():
class UserAdmin(BaseUserAdmin):
def get_fieldsets(self, request, obj=None):
fieldsets = list(super(UserAdmin, self).get_fieldsets(request, obj))
# update the `fieldsets` with your specific fields
fieldsets.append(
('Personal info', {'fields': ('bdate', 'website', 'location')}))
return fieldsets
I gave the editors such permissions:
auth | user | can add/change user - ON
auth | permissions | can add/change permissions - OFF
Still, when editing, they can change their permissions (and allow themselves actions they shouldn't do). I've found a ticket from 2yrs ago: http://code.djangoproject.com/ticket/6519 and it still works this way.
How to allow user edition (email, passwords, etc..) but block permissions change?
The code below gives you ability to override the formset, this essentially limits the ability for non-superusers to edit permissions. They can still create users, but they just can't modify permissions. They can even edit users just fine.
#admin.py
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.admin import UserAdmin
class UserAdmin(UserAdmin):
# this is for only editing/change/update only please keep in mind that
# the user can create superuser that can do everything
# so we will do the same for the add_view too
def change_view(self, request, object_id):
# we want to limit the ability of the normal user to edit permissions.
if request.user.is_superuser:
self.fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Groups'), {'fields': ('groups',)}),
)
else:
self.fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
#(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
#(_('Groups'), {'fields': ('groups',)}),
)
# this is for creating
def add_view(self, request):
# we want to limit the ability of the normal user to create permissions.
if request.user.is_superuser:
self.add_fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Groups'), {'fields': ('groups',)}),
)
else:
self.add_fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
#(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
#(_('Groups'), {'fields': ('groups',)}),
)
return super(UserAdmin, self).change_view(request)
by saying "normal user" I'm assuming that you know it means user that has is_istaff permission who can access admin site.
Your current approach isn't going to work I'm afraid.
From the Django docs:
If you have permission to add users, you have the power to create superusers, which can then, in turn, change other users.
So if you manage to block the editors from changing permissions, it will not help, because they could still create superusers that can.