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')
Related
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 created a customUser model so that the default User is overwritten.
This is my customUser model:
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
from crispy_forms.helper import FormHelper
class CustomUserCreationForm(UserCreationForm):
helper = FormHelper()
class Meta(UserCreationForm):
model = CustomUser
fields = ('first_name', 'username', 'email', 'last_name', 'organization', 'location', 'postcode', 'phone', 'agree_conditions')
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm):
model = CustomUser
fields = ('username', 'email', 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
Everything works perfectly however I am not able to change the order of the "User default" fields.
I know how to re-order the form fields, I can simply change the order in the fields = (a, b, c). For example if I want "c" to appear before "a" and "b" in the form, I can do: fields = (c, a, b).
HOWVER I want to move up the password and password confirmation
but I do not know how to do so because I do know know their name in the User default model.
Ideally I want this:
fields = ('username', 'email', 'PASSWORD_WHICH_I_DONT_KNOW_THE_NAME', 'CONFIRMPASSWORD_WHICH_I_DONT_KNOW_THE_NAME' 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
Solved, it was silly of me.
I inspected the HTML of the form and found out that:
the "PASSWORD_WHICH_I_DONT_KNOW_THE_NAME" is named by default: password1
The "CONFIRMPASSWORD_WHICH_I_DONT_KNOW_THE_NAME" is named by default: password2
So it will be:
fields = ('username', 'email', 'password1', 'password2' 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
I'm trying to show user group name instead of it's id .
I have this serilizer class for user class and I used this User = auth.get_user_model() for user Model
but it show NULL instead of theier name .. when i delete get_groups function i will see related groups id why ?
what is correct way to get all users group?
class UserSerializer(ModelSerializer):
groups = SerializerMethodField()
def get_groups(self, obj):
return obj.groups.name
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'date_joined',
'last_login',
'is_staff',
'is_superuser',
'is_active',
'groups'
]
try it
groups = serializers.SlugRelatedField(many=True, read_only=True, slug_field="name")
Try this,
class UserSerializer(ModelSerializer):
def get_groups(self, obj):
return obj.groups.values_list('name', flat=True)
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'date_joined',
'last_login',
'is_staff',
'is_superuser',
'is_active',
'groups'
]
This would return all grups related to paricular user as list
Example:
In [5]: user =User.objects.get(id=1)
In [6]: user.groups.values_list('name',flat=True)
Out[6]: ['grp_name_1', 'grp_name_2']
In [8]: user.groups.all()
Out[8]: [<Group: grp_name_1>, <Group: grp_name_2>]
I’ve created a custom user object in my Django app, but don’t have control over user permissions. I believe this is because the Users link isn’t appearing in the Auth section of the Django admin site, where permissions are usually controlled.
Why would it not be showing up?
This is from my models.py file:
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
class UserManager(BaseUserManager):
def create_user(self, username, password=None):
"""
Creates and saves a user with the given username.
"""
user = self.model()
user.username = username
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, password):
"""
Creates and saves a superuser with the given username.
"""
user = self.create_user(username, password=password)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class FooUser(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=40, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
my_time_field = models.DateTimeField(null=True, blank=True)
USERNAME_FIELD = 'username'
objects = UserManager()
class Meta:
app_label = 'foo'
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return self.is_admin
In other apps I extend the user model further as needed:
class CocoUser(FooUser):
mobile_number = models.CharField(max_length=64, blank=True, null=True)
first_name = models.CharField(max_length=128, blank=True, null=True)
last_name = models.CharField(max_length=128, blank=True, null=True)
email = models.CharField(max_length=128, blank=True, null=True)
This is from my settings.py file:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'kohlab.force_logout.ForceLogoutMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.humanize',
'django.contrib.messages',
'django_cleanup',
'south',
'myapp',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"django.core.context_processors.static",
"kohlab.context_processors.site",
)
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
AUTH_USER_MODEL = ‘myapp.FooUser’
This is from my urls.py file:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
)
This is from my admin.py file:
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from coco.models import CocoUser
class CocoUserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required fields, plus a repeated password."""
class Meta:
model = CocoUser
fields = ('mobile_number', 'email', 'first_name', 'last_name',)
class CocoUserChangeForm(forms.ModelForm):
"""
A form for updating users. Includes all the fields on the user, but replaces the password field with the initial one.
"""
class Meta:
model = CocoUser
fields = ['is_admin', 'is_staff', 'mobile_number', 'first_name', 'last_name', 'email']
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"]
class CocoUserAdmin(UserAdmin):
# The forms to add and change user instances
form = CocoUserChangeForm
add_form = CocoUserCreationForm
# The fields to be used in displaying the CocoUser model.
# These override the definitions on the base UserAdmin that reference specific fields on auth.User.
list_display = ('id', 'first_name', 'last_name', 'email', 'mobile_number', 'is_admin', 'is_staff',)
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('is_admin', 'is_staff', 'mobile_number', 'first_name', 'last_name', 'email',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('mobile_number', 'email', 'first_name', 'last_name',)}
),
)
search_fields = ('id', 'mobile_number', 'email', 'first_name', 'last_name',)
ordering = ('last_name', 'first_name',)
filter_horizontal = ()
# Now register the new UserAdmin...
admin.site.register(CocoUser, CocoUserAdmin)
In the end, the solution was rather simple. I had to adjust my CocoUserAdmin’s fieldsets to expose the permissions.
With a custom class like that, there will be no Users link in the Auth section, because the custom class takes over -- including permissions. These settings won’t be evident though, unless 'groups' and 'user_permissions' are added to fieldsets.
That CocoUserAdmin fieldsets fix is the key. Along the way, I converted FooUser to be a subclass of AbstractUser. This might have been unnecessary; the permissions may well have been there when CocoUser was a subclass of AbstractBaseUser too, but I’m not sure.
From my final models.py file:
from django.contrib.auth.models import AbstractUser
from django.db import models
class FooUser(AbstractUser):
my_time_field = models.DateTimeField(null=True, blank=True)
class CocoUser(FooUser):
mobile_number = models.CharField(max_length=64, blank=True, null=True)
From my final admin.py file:
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from coco.models import CocoUser
class CocoUserCreationForm(forms.ModelForm):
"""A form for creating new users."""
class Meta:
model = CocoUser
fields = ('username', 'mobile_number', 'email', 'first_name', 'last_name',)
class CocoUserChangeForm(forms.ModelForm):
"""
A form for updating users. Includes all the fields on the user.
"""
class Meta:
model = CocoUser
fields = ['username', 'password', 'first_name', 'last_name', 'email', 'is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions', 'last_login', 'date_joined',
'my_time_field', 'mobile_number',]
class CocoUserAdmin(UserAdmin):
# The forms to add and change user instances
form = CocoUserChangeForm
add_form = CocoUserCreationForm
# The fields to be used in displaying the CocoUser model.
# These override the definitions on the base UserAdmin that reference specific fields on auth.User.
list_display = ('id', 'first_name', 'last_name', 'email', 'mobile_number',)
fieldsets = (
(None, {'fields': ('username', 'password',)}),
('Personal info', {'fields': ('first_name', 'last_name', 'email', 'date_joined', 'last_login', 'is_online',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions',)}),
('Coco', {'fields': ('my_time_field', 'mobile_number',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'mobile_number', 'email', 'first_name', 'last_name',)}
),
)
search_fields = ('id', 'mobile_number', 'email', 'first_name', 'last_name',)
ordering = ('last_name', 'first_name',)
class Meta:
model = CocoUser
I derived from AbstractUser and had the same problem. No Users in Auth section.
That because I forgot to register my custom user admin class.
Maybe you need to register your FooUser admin class first.
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.