Code

Opened 12 months ago

Closed 11 months ago

Last modified 11 months ago

#20367 closed Bug (invalid)

Custom User model, wrong field order in Django admin form

Reported by: dyve Owned by: nobody
Component: contrib.admin Version: 1.5
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Create a Custom user that just adds a few fields. Do this by inheriting django.contrib.auth.models.AbstractUser

Here is my code:

class User(AbstractUser):
    is_admin = models.BooleanField(default=False, verbose_name=ugettext_lazy('is admin'))
    hide_name = models.BooleanField(default=False, verbose_name=ugettext_lazy('hide name'))
    country = models.ForeignKey(Country, null=True, blank=True, verbose_name=ugettext_lazy('country'))
    language = LanguageField(null=True, blank=True)
    share_photos = models.BooleanField(default=True, verbose_name=ugettext_lazy('share photo\'s with other users'))

when adding/editing a user in the Django admin, I would expect to see the standard User fields in the same order as when using django.contrib.auth.models.User, and my own (added) fields below them).

Instead, the inherited fields are in an order tha makes no sense, starting with password. See screenshot.

Attachments (1)

django_custom_user_admin_form.png (94.9 KB) - added by dyve 12 months ago.
screenshot of admin form

Download all attachments as: .zip

Change History (5)

Changed 12 months ago by dyve

screenshot of admin form

comment:1 Changed 12 months ago by charettes

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to invalid
  • Status changed from new to closed

Form fields default order is based on model field definition order.

In your case User subclass AbstractUser which subclass (AbstractBaseUser, PermissionsMixin) thus fields are defined in the following order (AbstractBaseUser, PermissionsMixin, AbstractUser, User) hence the behavior you're describing.

There's no API at the model level to specify field order when inheriting fields from abstract models. However ModelForm provide an option to specify form fields order.

To achieve what you expect from the admin you should create a ModelForm subclass and specify the field order you'd like to display. Then attach this form class to your custom user ModelAdmin. See the documentation for more details.

May I suggest you use support channels prior to report a bug next time. You'd get feedback way faster this way.

comment:2 Changed 11 months ago by dyve

  • Resolution invalid deleted
  • Status changed from closed to new

Thank you for adding information to this report. I should have mentioned that I do know how to fix this in my specific app, my bug report was not meant as a support request, but a sincere attempt to raise the quality of the admin interface.

I still insist that this behavior is a bug in Django admin, and politely request that this be looked at again. Why do I think this?

In the documentation at https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-django-s-default-user, it says:

If you’re entirely happy with Django’s User model and you just want to add some additional profile information, you can simply subclass django.contrib.auth.models.AbstractUser and add your custom profile fields.

and a bit further on the same page, at https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-users-and-django-contrib-admin

If your custom User model extends django.contrib.auth.models.AbstractUser, you can use Django’s existing django.contrib.auth.admin.UserAdmin class. However, if your User model extends AbstractBaseUser, you’ll need to define a custom ModelAdmin class.

This suggests, and rightly so, that when extending AsbtractUser, UserAdmin should work as expected (which is the way it works when using vanilla django.contrib.auth.models.User).

In https://github.com/django/django/blob/master/django/contrib/auth/models.py, User is nothing more than a class that extends AbstractUser, so this should not be impossible.

So again, I vote that when building on AbstractUser, the default django.contrib.admin behaviour should be that the UserChangeForm, when working with an AbstractUser based object:

  • starts with the AbstractUser fields in the established Django order
  • then the fields that may have been added

comment:3 Changed 11 months ago by lukeplant

  • Resolution set to invalid
  • Status changed from new to closed

It sounds like you are not using django.contrib.auth.admin.UserAdmin. You have missed the part of the docs that says "you can use Django’s existing django.contrib.auth.admin.UserAdmin class". If you are using UserAdmin, I can't explain your observations and screenshot.

If you are not, I don't how you expect the admin to automatically produce something similar to UserAdmin without you asking it to. While User is nothing more than a class that extends AbstractUser, its admin definition is much more involved, and if you haven't used it, especially when the docs tell you to, you can't expect the admin interface to look the same.

There is no way that we are going to hard code special support in contrib.admin for things that happened to be derived from AbstractUser!

comment:4 Changed 11 months ago by dyve

My apologies, I have misunderstood and/or misread. Explicitly using UserAdmin is indeed the solution, and a logical one.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.