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.
Related
I encountered a problem to migrate this model and this admin
python manage.py makemigrations
This error occurs
for model in model_or_iterable:
TypeError: 'MediaDefiningClass' object is not iterable
this is my admin
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import Group
from .models import User, Province
class MyUserAdmin(UserAdmin):
fields = (
(None, {'fields': ('username', 'password')}),
'Personal info', {'fields': ('first_name', 'last_name', 'phone_number', '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', 'phone_number', 'password1', 'password2'),
}),
)
list_display = ('username', 'phone_number', 'email', 'is_staff')
search_fields = ('username_exact',)
ordering = ('-id',)
def get_search_results(self, request, queryset, search_term):
queryset, my_have_duplicates = super().get_search_results(
request, queryset, search_term
)
try:
search_term_as_int = int(search_term)
except ValueError:
pass
else:
queryset |= self.model.objects.filter(phone_number=search_term_as_int)
return queryset, my_have_duplicates
admin.site.unregister(Group)
admin.site.register(Province)
admin.site.register(User)
admin.site.register(MyUserAdmin)
But the program has encountered an error
for model in model_or_iterable:
TypeError: 'MediaDefiningClass' object is not iterable
I need to disable adding new users in the admin panel once the number of users exceeds a particular value. The code below works to remove the "add user" button when I test it with hard coded integers. However, this line does not appear to be returning the count of users without hard coding a count: usercount = CustomUser.objects.count()
Any ideas for getting the count of users already added?
models.py:
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import Group
from django.contrib import admin
from django.db.models import Count
from django.db.models.signals import post_save
class CustomUser(AbstractUser):
full_name = models.CharField(max_length=250, null=True)
age = models.PositiveIntegerField(null=True, blank=True)
employee_type = models.ForeignKey(Group, null=True, on_delete=models.SET_NULL, default=1)
is_active = models.BooleanField(null=False, default=True)
# disable add new user in the admin panel
class RemoveAddNew(admin.ModelAdmin):
usercount = CustomUser.objects.count()
if usercount > 5:
def has_add_permission(self, request, obj=None):
return False
admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser, RemoveAddNew
class CustomUserAdmin(RemoveAddNew, UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['username', 'email', 'full_name', 'age', 'is_staff', 'is_active']
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('full_name', 'age', )}),
)
add_fieldsets = UserAdmin.add_fieldsets + (
(None, {'fields': ('email','full_name', 'age', 'employee_type', 'is_active')}),
)
admin.site.register(CustomUser,CustomUserAdmin)
I think you over code it. My solution is simpler and shorter:
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['username', 'email', 'full_name', 'age', 'is_staff', 'is_active']
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('full_name', 'age', )}),
)
add_fieldsets = UserAdmin.add_fieldsets + (
(None, {'fields': ('email','full_name', 'age', 'employee_type', 'is_active')}),
)
def has_add_permission(self, request):
return CustomUser.objects.count() < 6
admin.site.register(CustomUser,CustomUserAdmin)
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
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')
I have a custom user object GameUser, a profile UserInfo that attaches to each user with information, and a Weapon model that each profile gets associated to, but can only have one at a time.
I want to be able to look up and existing GameUser in my admin interface and, in the change form, have the option to create an associate a new Weapon to that UserInfo profile.
Here's my models:
class GameUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField()
# ...etc
class UserInfo(models.Model):
first = models.CharField(max_length=30)
last = models.CharField(max_length=30)
# ...etc
# relations
user = models.OneToOneField(GameUser)
weapon = models.ForeignKey('Weapon', null=True)
class Weapon(models.Model):
name = models.CharField(max_length=20)
# ...etc
And my admin.py:
class GameUserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
class Meta:
model = GameUser
fields = ('email', 'password')
def clean_password(self):
return self.initial["password"]
class GameUserAdmin(UserAdmin):
form = GameUserChangeForm
list_display = ('email', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_admin',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
class UserInfoAdmin(admin.ModelAdmin):
fieldsets = [
('Personal Information', {'fields': [
'first', 'last']
}),
# ... etc
]
list_display = ('first', 'last')
search_fields = ['city', 'state']
admin.site.register(UserInfo, UserInfoAdmin)
admin.site.register(GameUser, GameUserAdmin)
If there is a Weapon associated with that GameInfo, I'd like to display it there inline. If not, I'd like to be able to create a new Weapon object for that GameInfo and set its fields.
I should mention I'm not married to Weapon being a ForiegnKey - it could certainly be a OneToOneField as well if that makes it easier.
What is the right way for me to do this in Django?