Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No “Users” link in “Auth” section of Django admin site

Tags:

python

django

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.

my admin issue

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)
like image 692
Dylan Avatar asked Jun 25 '14 19:06

Dylan


People also ask

How do I authenticate a user in Django?

auth import authenticate, login def my_view(request): username = request. POST['username'] password = request. POST['password'] user = authenticate(username=username, password=password) if user is not None: if user. is_active: login(request, user) # Redirect to a success page.

Which types of users are allowed to login to the Django Administration site?

Only one class of user exists in Django's authentication framework, i.e., 'superusers' or admin 'staff' users are just user objects with special attributes set, not different classes of user objects. The primary attributes of the default user are: username. password.

How do I get user permissions in Django?

Add Permissions to a Group If you are using AbstractUser in Django, you must add AUTH_USER_MODEL = 'YourAppName. YourClassName' . This way, you are telling Django to use our custom user model instead of the default one. The code below should go in your admin.py file so that you can see your user model.

How do I add permission to Django admin?

Test the 'view' permission is added to all modelsUsing #3 for Django 1.7 only creates the permission objects if the model doesn't already exist. Is there a way to create a migration (or something else) to create the permission objects for existing models?


1 Answers

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
like image 64
Dylan Avatar answered Oct 16 '22 05:10

Dylan