Fieldsets don't do anything in admin django - python

I'm learning Django and found that we can use fieldsets to customise the way admin creation form looks like. Here is the code I'am using:
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ('email', 'age', 'is_staff', 'is_active',)
list_filter = ('email', 'age', 'is_staff', 'is_active',)
fieldsets = (
('Advanced options', {
'classes': ('wide',),
'fields': ('email', 'age', 'is_staff', 'is_active',),
}),
)
admin.site.register(CustomUser, CustomUserAdmin)
Here is the result:
As you can see this "fieldsets" does nothing for this creation page. And if I completely remove this "fieldsets" nothing will change. What I did wrong here? I want my fieldsets work.
Thank you!

The UserAdmin separates the add action (user creation) form other actions. This is because it only wants to deal with username and password and then the rest of the fields.
So the UserAdmin does some special work and you have both fieldsets and add_fieldsets.
Below is copied from a customer user in one of my projects. It has a required field on the User model called display_name and so it must be submitted via the admin as well.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
from django.utils.translation import gettext as _
from core import models
from core.forms.admin import UserCreationForm
#admin.register(models.User)
class UserAdmin(AuthUserAdmin):
fieldsets = (
(None, {"fields": ("username", "password")}),
(_("Personal info"), {"fields": ("display_name", "email")}),
(
_("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", "password1", "password2"),},
),
(_("Profile related"), {"fields": ("display_name",)}),
)
add_form = UserCreationForm

Related

Django Admin restrict users to be added to more than one group

I am creating a customised Django Admin and I want to restrict users to be associated to no more than one group. I am using Django 4.1 and Python 3.11
admin.py:
from django.contrib import admin
from typing import Set
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.utils.translation import gettext_lazy as _
from .models import User
#admin.register(User)
class UserAdmin(DjangoUserAdmin):
ordering = ('is_staff', 'is_active', 'email', 'organisation')
list_display = ('email', 'name', 'organisation', 'is_staff', 'is_active', 'is_superuser', 'date_joined')
fieldsets = (
("Personal info", {'fields': ('name', 'email', 'password', 'organisation')}),
("Permissions", {'fields': (
# 'is_active',
# 'is_staff',
# 'is_superuser',
'groups',
# 'user_permissions'
)}))
add_fieldsets = (
(None, {'classes': ('wide',), 'fields': ('name', 'email', 'password1', 'password2', 'organisation')}),
)
Is there a way to change this in the admin code?
Or it is possible to disable the group widget ("Choose all") on the page? if so which html page is used for groups?
Yes, it is possible to restrict the number of groups a user can be associated with in Django. One way to do this is to override the save_model() method in your custom UserAdmin class and perform the check there, so:
#admin.register(User)
class UserAdmin(DjangoUserAdmin):
# ... other stuff
# ... other stuff
def save_model(self, request, obj, form, change):
if obj.groups.count() > 1:
self.message_user(request, _('Users can only be associated with one group.'), level=messages.ERROR)
else:
super().save_model(request, obj, form, change)

How to change navbar contents of the User Change page in Django admin?

I'm working on Django.And I wanted to change the navbar content in the User Change Page in the Django admin as marked with red color in the pic :
And my admin file is :
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
change_form_template = 'change_form.html'
add_form_template='add_form.html'
list_display = ('first_name','last_name','email','is_staff', 'is_active',)
list_filter = ('first_name','email', 'is_staff', 'is_active',)
search_fields = ('email','first_name','last_name','a1','a2','city','state','pincode')
ordering = ('first_name',)
add_fieldsets = (
('Personal Information', {
# To create a section with name 'Personal Information' with mentioned fields
'description': "",
'classes': ('wide',), # To make char fields and text fields of a specific size
'fields': (('first_name','last_name'),'email','a1','a2','city','state','pincode','check',
'password1', 'password2',)}
),
('Permissions',{
'description': "",
'classes': ('wide', 'collapse'),
'fields':( 'is_staff', 'is_active','date_joined')}),
)
It is same as the default Django user model name so only I want to change it.
So it can be changed or is it permanent??
Thanks in advance!!
Yes it can be changed and for that you dont need to make any changes to your admin file but instead in the models.py file.In the models.py file you have to add a Meta class to your user model and define verbose_name in it like this:
class Meta:
verbose_name="Type here your desired name instead of name users"
And then that navbar content will be changed as you wished.

Serial number in Django admin list view

I have the following list view in Django admin. How do I show serial number for every entry? Meaning numbering the list given in the list below. Also, this serial number should also take into account the pagination of the list.
Here is the model:
class Staff(User):
INITIALS = (
("MR", "Mr."),
("MRS", "Mrs."),
("MS", "Ms."),
)
initials = models.CharField(
max_length=10,
choices=INITIALS,
default="MR"
)
def __str__(self):
return self.initials+" "+self.first_name+" "+self.last_name
# Control model features
class Meta:
verbose_name = 'Staff'
verbose_name_plural = 'Staff'
Here is the admin model:
#admin.register(Staff)
class StaffAdmin(BaseUserAdmin):
add_form = StaffCreationForm
add_fieldsets = (
(None, {
'fields': ('email', 'password1', 'password2', 'first_name', 'last_name','institute','groups')
}),
)
fieldsets = (
(None, {'fields': ('email', 'first_name', 'last_name','password','groups','institute')}),
)
list_filter = ('institute',)
inlines = [
SubjectTeacher
]
list_display = ("first_name", "last_name")
list_per_page = 5
I don't see a "serial number" field in your Staff model but I believe you are referring to its id
in your admin model you should be able to just include id to add the "serial number"
#admin.register(Staff)
class StaffAdmin(BaseUserAdmin):
add_form = StaffCreationForm
add_fieldsets = (
(None, {
'fields': ('email', 'password1', 'password2', 'first_name', 'last_name','institute','groups')
}),
)
fieldsets = (
(None, {'fields': ('email', 'first_name', 'last_name','password','groups','institute')}),
)
list_filter = ('institute',)
inlines = [
SubjectTeacher
]
list_display = ("first_name", "last_name", "id")
list_per_page = 5
In the list view you also need to include the serial number. You should share with us how you are expressing this view in code, instead of the screen shot to clarify the question

Extendings Django's UserCreationForm

I'm trying to extend Django's django.contrib.auth.forms.UserCreationForm to include email and name fields. My similar extension of the UserChangeForm works fine, but UserCreationForm still only shows the default username, password1, and password2 fields. Any ideas what I'm doing wrong?
forms.py
class AuthorCreation(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2',
'first_name', 'last_name', 'email', 'groups', 'is_staff')
class AuthorChange(UserChangeForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name',
'email', 'password', 'groups', 'is_staff')
admin.py
class AuthorAdmin(UserAdmin):
"""Admin class for creating and managing Authors"""
inlines = [AuthorInline]
fieldsets = (
(None, {
'fields': ('username', ('first_name', 'last_name'),
'email', 'password', 'groups', 'is_staff')
}),
)
class Media:
css = {
'all': [
'css/codenotes-admin.css',
]
}
def get_form(self, request, obj=None, **kwargs):
if obj is None:
return forms.AuthorCreation
else:
return forms.AuthorChange
admin.site.unregister(User)
admin.site.register(User, AuthorAdmin)
Again, the AuthorChangeForm correctly displays all the fields, but AuthorCreationForm only displays the username, password1, and password2 fields (plus the inline forms, which works fine on both).
I assume the problem is with the fieldsets, but I can't figure it out from the docs.
I figured out the solution. The problem was, as I suspected, the fieldsets. It turns out that the UserAdmin class inherits has TWO fieldsets that need to be overridden, fieldsets and add_fieldsets. I didn't see this mentioned anywhere in the docs (maybe I just missed it); I had to dig through the source to find it. As the name suggests, add_fieldsets is used when adding a new user. The following admin class works as expected:
admin.py
class AuthorAdmin(UserAdmin):
"""Admin class for creating and managing Authors"""
inlines = [AuthorInline]
fieldsets = (
(None, {
'fields': ('username', ('first_name', 'last_name'),
'email', 'password', 'groups', 'is_staff')
}),
)
add_fieldsets = (
(None, {
'fields': ('username', 'password1', 'password2',
('first_name', 'last_name'),
'email', 'groups', 'is_staff'),
}),
)
class Media:
css = {
'all': [
'css/codenotes-admin.css',
]
}
def get_form(self, request, obj=None, **kwargs):
if obj is None:
return forms.AuthorCreation
else:
return forms.AuthorChange
admin.site.unregister(User)
admin.site.register(User, AuthorAdmin)
From the Django doc:
class UserCreationForm¶ A ModelForm for creating a new user.
It has three fields: username (from the user model), password1, and
password2. It verifies that password1 and password2 match, validates
the password using validate_password(), and sets the user’s password
using set_password().
So it seems you have to create the extra fields yourself like this:
class AuthorCreation(UserCreationForm):
first_name = forms.CharField(required=True, label="First Name")
... etc ...
class Meta:
model = User
fields = ('username', 'password1', 'password2',
'first_name', 'last_name', 'email', 'groups', 'is_staff')

Adding extra fields to UserAdmin

i have this custom class
class CustomUserAdmin(UserAdmin):
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email', 'password1', 'password2', 'location')}
),
)
fieldsets = (
(None, {'fields': ('username', 'password')}),
(('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'location')}),
(('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(('Important dates'), {'fields': ('last_login', 'date_joined')}),
(('Groups'), {'fields': ('groups',)}),
)
#UserAdmin.list_display += ('location',)
add_form = MyUserCreationForm
form = MyUserChangeForm
It works fine, untill i uncomment this line
UserAdmin.list_display += ('location',)
then it gives me this error:
CustomUserAdmin.list_display[5], 'location' is not a callable or an attribute of 'CustomUserAdmin' or found in the model 'User'.
any help?
[Edit]
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
location = models.CharField(max_length=30)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
You are not going to modify UserAdmin right?
Supposing that location is an actual field of CustomUser, try to use
list_display = UserAdmin.list_display + ('location',)
EDIT: simpler answer
Use the standard django way to show custom things in the list_display:
class CustomUserAdmin(UserAdmin):
# other things
def user_location(self, u):
try:
return u.get_profile().location
except:
return ''
user_location.short_description = 'Location'
list_display = UserAdmin.list_display + ('user_location',)
EDIT: more info
Anyway, if you are extending the UserForm just for the sake of adding the profile fields, you should look into this link: http://www.thenestedfloat.com/articles/displaying-custom-user-profile-fields-in-djangos-admin/index.html to take advantages of inlines and avoid recreating the whole Form from scratch.

Categories