152👍
After digging around the Django source code for a while, I found a working soultion. I am not totally happy with this solution, but it seems to work. Feel free to suggest better solutions!
Django uses UserAdmin
to render the nice admin look for User
model. By just using this in our admin.py
-file, we can get the same look for our model.
from django.contrib.auth.admin import UserAdmin
admin.site.register(MyUser, UserAdmin)
However, this alone is probably not a good solution, since Django Admin will not display any of your special fields. There are two reasons for this:
UserAdmin
usesUserChangeForm
as the form to be used when modifying the object, which in its turn usesUser
as its model.UserAdmin
defines aformsets
-property, later used byUserChangeForm
, which does not include your special fields.
So, I created a special change-form which overloads the Meta inner-class so that the change form uses the correct model. I also had to overload UserAdmin
to add my special fields to the fieldset, which is the part of this solution I dislike a bit, since it looks a bit ugly. Feel free to suggest improvements!
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = MyUser
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('some_extra_data',)}),
)
admin.site.register(MyUser, MyUserAdmin)
62👍
A simpler solution, admin.py:
from django.contrib.auth.admin import UserAdmin
from main.models import MyUser
class MyUserAdmin(UserAdmin):
model = MyUser
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('some_extra_data',)}),
)
admin.site.register(MyUser, MyUserAdmin)
Django will correctly reference MyUser model for creation and modification.
I’m using Django 1.6.2.
- [Django]-Django.contrib.gis.db.backends.postgis vs django.db.backends.postgresql_psycopg2
- [Django]-Python/Django: log to console under runserver, log to file under Apache
- [Django]-Django-way for building a "News Feed" / "Status update" / "Activity Stream"
58👍
nico’s answer has been extremely helpful but I found Django still references the User model when creating a new user.
Ticket #19353 references this problem.
In order to fix it i had to make a few more additions to admin.py
admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from main.models import MyUser
from django import forms
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = MyUser
class MyUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = MyUser
def clean_username(self):
username = self.cleaned_data['username']
try:
MyUser.objects.get(username=username)
except MyUser.DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('extra_field1', 'extra_field2',)}),
)
admin.site.register(MyUser, MyUserAdmin)
- [Django]-Github issues api 401, why? (django)
- [Django]-Why does django's prefetch_related() only work with all() and not filter()?
- [Django]-How to set and get cookies in Django?
13👍
cesc’s answer wasn’t working for me when I attempted to add a custom field to the creation form. Perhaps it’s changed since 1.6.2? Either way, I found adding the field to both fieldsets and add_fieldsets did the trick.
ADDITIONAL_USER_FIELDS = (
(None, {'fields': ('some_additional_field',)}),
)
class MyUserAdmin(UserAdmin):
model = MyUser
add_fieldsets = UserAdmin.add_fieldsets + ADDITIONAL_USER_FIELDS
fieldsets = UserAdmin.fieldsets + ADDITIONAL_USER_FIELDS
admin.site.register(MyUser, MyUserAdmin)
- [Django]-How to serve media files on Django production environment?
- [Django]-Serving Media files during deployment in django 1.8
- [Django]-Embedding JSON objects in script tags
4👍
If you want to hook into the default sections instead of copying and pasting Django core code, you can extend the UserAdmin
class and inject your fields into the fieldsets
attribute as wished.
In Django v4.0.x, the fieldsets
tuple you are modifying looks like this:
fieldsets = (
(None, {"fields": ("username", "password")}),
(_("Personal info"), {"fields": ("first_name", "last_name", "email")}),
(
_("Permissions"),
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"groups",
"user_permissions",
),
},
),
(_("Important dates"), {"fields": ("last_login", "date_joined")}),
)
Source: https://github.com/django/django/blob/stable/4.0.x/django/contrib/auth/admin.py#L47-L63
Now, for example, to add a custom role
field:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User
class UserAdmin(BaseUserAdmin):
fieldsets = BaseUserAdmin.fieldsets
fieldsets[0][1]['fields'] = fieldsets[0][1]['fields'] + (
'role',
)
admin.site.register(User, UserAdmin)
- [Django]-How can I change the default Django date template format?
- [Django]-Choose test database?
- [Django]-Cannot set Django to work with smtp.gmail.com
3👍
Another similar solution (Took from here):
from __future__ import unicode_literals
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _
from .models import User
class UserAdminWithExtraFields(UserAdmin):
def __init__(self, *args, **kwargs):
super(UserAdminWithExtraFields, self).__init__(*args, **kwargs)
abstract_fields = [field.name for field in AbstractUser._meta.fields]
user_fields = [field.name for field in self.model._meta.fields]
self.fieldsets += (
(_('Extra fields'), {
'fields': [
f for f in user_fields if (
f not in abstract_fields and
f != self.model._meta.pk.name
)
],
}),
)
admin.site.register(User, UserAdminWithExtraFields)
- [Django]-Using the reserved word "class" as field name in Django and Django REST Framework
- [Django]-AccessDenied when calling the CreateMultipartUpload operation in Django using django-storages and boto3
- [Django]-Django queries – id vs pk