Django UserAdmin customization - django

Within my Users page, I would like to add more column fields to display for each user.
By default, the User page shows username, first name, last name, email, and staff status, but I would also like to add the column "Chosen Groups" to be displayed as well.
Each user can be a part of zero or more groups, so I would like to show a list of all groups (or None) that each user is a part of.
I put something together but I am not sure how to actually get the group data and put it into a "string" form for the "Chosen Groups" column.
Here was my failed attempt...
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'email', 'first_name', 'last_name', 'date_joined', 'get_groups')
def get_groups(self, object):
#code...
#User is registered by default, need to unregister than register to apply custom updates to UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Here it is:
def get_groups(self, object):
return u', '.join(g.name for g in object.groups.all()) or 'None'
get_groups.short_description = 'Chosen Groups'
To reduce the number of sql queries you can also override the get_queryset() method:
def get_queryset(self, request):
qs = super(UserAdmin, self).get_queryset(request)
return qs.prefetch_related('groups')

Related

Django auth groups not finding groups and does not give permission to users, regardless of the group in which they are

I'm making a simple real estate app where the users must be separated into two different groups. A regular user and a broker. I'm using the Django admin backend for creating user groups. I'm also using a post_save signal to assign all the new users to the regular users' group. At first glance, it works well and in Django admin, it shows me that the user is in the corresponding group. But when I try to print self.request.user.groups the value is None. Also when I try to check if users have permission to do something, regardless of the permissions I gave the view I check always gives me 403 Forbidden regardless of whether the user has permission or not. I use class-based views and PermissionRequiredMixin respectively.
Here is my user model:
class DjangoEstatesUser(auth_models.AbstractBaseUser, auth_models.PermissionsMixin):
USERNAME_MAX_LENGTH = 30
username = models.CharField(
max_length=USERNAME_MAX_LENGTH,
unique=True,
)
date_joined = models.DateTimeField(
auto_now_add=True,
)
is_staff = models.BooleanField(
default=False,
)
USERNAME_FIELD = 'username'
objects = DjangoEstatesUserManager()
Also the signal for assigning the new users to a group:
#receiver(post_save, sender=DjangoEstatesUser)
def create_user_profile(sender, instance, created, **kwargs):
if created:
instance.groups.add(Group.objects.get(name='Users'))
and this is one view that I'm trying to restrict for different users:
class AddEstateView(auth_mixins.LoginRequiredMixin, auth_mixins.PermissionRequiredMixin, views.CreateView):
permission_required = 'auth_permission.add_estate'
template_name = 'main/estates/add_estate.html'
form_class = AddEstateForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_success_url(self):
return reverse_lazy('profile details', kwargs={'pk': self.object.user_id})
And these are the groups with the permissions.
brokers_group
and
users_group.
And these are my
db_tables
and auth_permission_table.
I can't figure out where I'm wrong or what I'm not doing right, any help will be appreciated!
Thank you in advance!
self.request.user.groups prints always None: that is a RelatedManager [Django-doc], not a QuerySet. Managers will print the model name with None, so for a Model named ModelName in app_name, it prints:
app_name.ModelName.None
You print the items with self.request.user.groups.all():
print(self.request.user.groups.all())

Looking for wagtail modeladmin PermissionHelper example

In "wagtail_hooks.py" I have the code below. As wagtail admin I can see the StudentModelAdmin, but as a user with restricted access to the admin interface I can't.
I would like to allow users with wagtail admin access and the specific permission below to access the student model admin. How do I go about creating the "CourseRegisterPermission" class?
from wagtail.contrib.modeladmin.options import (ModelAdmin, modeladmin_register)
from wagtail.wagtailcore import hooks
from .models import Participant
#hooks.register('register_permissions')
def view_course_registrations():
return Permission.objects.filter(codename="view_course_registrations")
class CourseRegisterPermission(PermissionHelper):
# how do I allow users with the permission to view course registrations
# to see the 'StudentModelAdmin" below?
class StudentModelAdmin(ModelAdmin):
model = Participant
menu_label = "Student Registrations"
menu_icon = "group"
search_fields = ('name', 'supervisor_name')
list_display = ('name', 'email')
list_filter = ('course',)
permission_helper_class = CourseRegisterPermission
I tried to find some examples of wagtail PermissionHelper but wasn't able to find any.
Any hint would be appreciated!
You can use the wagtail.contrib.modeladmin.helpers.PermissionHelper or wagtail.contrib.modeladmin.helpers.PagePermissionHelper permission helper classes from Wagtail's sources as an example. See methods like user_can_list, user_can_create, etc.
But... Are you sure that you need to define your own permission helper class? It seems to me that you can just create a new (or edit existing) group in the Wagtail admin and give required object permissions to your Participant model.
On my screenshot Programme is the model that I manage using ModelAdmin.
You can override some functions inside CourseRegisterPermission
class CourseRegisterPermission(PermissionHelper):
def user_can_list(self, user):
"""
Return a boolean to indicate whether `user` is permitted to access the
list view for self.model
"""
# this is just an example
return user.role == "driver"
def user_can_delete_obj(self, user, obj):
"""
Return a boolean to indicate whether `user` is permitted to 'delete'
a specific `self.model` instance.
"""
perm_codename = self.get_perm_codename('delete')
if obj.status > 0:
return False
if not self.user_has_specific_permission(user, perm_codename):
return False
if user.id == obj.id:
# users may not delete themselves
return False
You can also override the following functions:
def user_can_list(self, user):
def user_can_create(self, user):
def user_can_inspect_obj(self, user, obj):
def user_can_edit_obj(self, user, obj):
def user_can_delete_obj(self, user, obj):
def user_can_unpublish_obj(self, user, obj):
def user_can_copy_obj(self, user, obj):

Django hide fields only in CREATE object admin page

As subject, i want to hide some fields ONLY when users enter the 'CREATE' admin page for specific model.
I know that change list_display can hide fields in admin page, but it's a global setting which will take affect not only in 'CREATE' admin page, but also in 'UPDATE' admin page.
#admin.register(User)
class UserProfileAdmin(UserAdmin):
def get_fields(self, request, obj=None):
fields = super(UserProfileAdmin, self).get_fields(request, obj)
for field in fields:
if field == 'some_field_name' and obj is None:
continue
yield field
Copied from Exclude fields in Django admin for users other than superuser
def get_fieldsets(self, request, obj=None):
fieldsets = super(MediaAdmin, self).get_fieldsets(request, obj)
if not obj:
fieldsets = (
(u'other', {
'fields': ('media_public_id',)
}),
)
return fieldsets
Django now has a get_exclude method on ModelAdmin for excluding fields programmatically.
It takes the current request and the object (if any) as argument. In your case, the object argument will be none if it's a "create" page so you can use that like so:
class MyModelAdmin(admin.ModelAdmin):
def get_exclude(self, request, obj=None):
excluded = super().get_exclude(request, obj) or [] # get overall excluded fields
if not obj: # if it's a create, so no object yet
return excluded + ['extra_field_to_exclude']
return excluded # otherwise return the default excluded fields if any

Django admin - change permissions list

Is there any possibility to change permissions list in user edit page? I don't wan't to show all of permissions for example admin log entry or auth group etc.
How can I modify a main queryset to exclude some of it?
I got the idea from this topic, which also answer your question, but it's not that clear.
You have to overwrite the queryset of user permissions in the UserAdmin form used for visualization.
To do this, the easiest way is to create a subclass of UserAdmin and overwrite the get_form method:
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
class MyUserAdmin(UserAdmin):
def get_form(self, request, obj=None, **kwargs):
# Get form from original UserAdmin.
form = super(MyUserAdmin, self).get_form(request, obj, **kwargs)
if 'user_permissions' in form.base_fields:
permissions = form.base_fields['user_permissions']
permissions.queryset = permissions.queryset.filter(content_type__name='log entry')
return form
You can change the filter of your queryset for whatever you want:
Examples:
# Exclude admin and auth.
permissions.queryset = permissions.queryset.exclude(content_type__app_label__in=['admin', 'auth'])
# Only view permissions of desired models (Can be your models or Django's)
permissions.queryset = permissions.queryset.filter(content_type__model__in=['blog', 'post', 'user', 'group'])
After you create your class, you have to register your User model with your newly created Admin:
admin.site.unregister(User) # You must unregister first
admin.site.register(User, MyUserAdmin)
Edit:
I added comment from Maik Hoepfel, because this code made django crashed when creating new user.
You can do the same with the permission list in your Group edit page, but you have to create another Admin that extends from GroupAdmin, and change form.base_fields['user_permissions'] with form.base_fields['permissions']
Renato's answer is almost perfect. The Django Admin makes adding a user a two-step process with the same form, and his code fails with a KeyError for 'user_permissions' in the first step.
The fix is easy enough, just use the code below instead:
def get_form(self, request, obj=None, **kwargs):
form = super(MyUserAdmin, self).get_form(request, obj, **kwargs)
# adding a User via the Admin doesn't include the permissions at first
if 'user_permissions' in form.base_fields:
permissions = form.base_fields['user_permissions']
permissions.queryset = permissions.queryset.filter(content_type__name='log entry')
return form

django users and groups - show group membership in admin?

The Django Admin's User management gives us easy access to setting a User's group allegiances via the list for picking the Groups. This is the ManyToMany relationship default widget for assignment. And for the most part that's nice for User creation from the get go.
However, say I have a huge number of users and groups, I'd like the chance to view and manage group membership by clicking on the Group in the admin and then seeing all the members in a similar picker (or via the horizontal widget).
Is there a built-in Django method/trick to show ManyToMany relations in "reverse?"
Setting group assignment is fine from the User adminform on User creation. But this can be a big pain to find and manage once users and groups are well established.
I guess the workaround is to make my own view to show group members, I just wanted to see if there was some trick I could do with inlines or something in the admin.
Try to use this snippet. It's customisation example of contrib.auth app admin part.
# utils/admin_auth.py
# -*- coding: utf-8 -*-
from django.utils.safestring import mark_safe
from django.contrib.auth.models import User, Group
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from django.contrib import admin
def roles(self):
#short_name = unicode # function to get group name
short_name = lambda x:unicode(x)[:1].upper() # first letter of a group
p = sorted([u"<a title='%s'>%s</a>" % (x, short_name(x)) for x in self.groups.all()])
if self.user_permissions.count(): p += ['+']
value = ', '.join(p)
return mark_safe("<nobr>%s</nobr>" % value)
roles.allow_tags = True
roles.short_description = u'Groups'
def last(self):
fmt = "%b %d, %H:%M"
#fmt = "%Y %b %d, %H:%M:%S"
value = self.last_login.strftime(fmt)
return mark_safe("<nobr>%s</nobr>" % value)
last.allow_tags = True
last.admin_order_field = 'last_login'
def adm(self):
return self.is_superuser
adm.boolean = True
adm.admin_order_field = 'is_superuser'
def staff(self):
return self.is_staff
staff.boolean = True
staff.admin_order_field = 'is_staff'
from django.core.urlresolvers import reverse
def persons(self):
return ', '.join(['%s' % (reverse('admin:auth_user_change', args=(x.id,)), x.username) for x in self.user_set.all().order_by('username')])
persons.allow_tags = True
class UserAdmin(UserAdmin):
list_display = ['username', 'email', 'first_name', 'last_name', 'is_active', staff, adm, roles, last]
list_filter = ['groups', 'is_staff', 'is_superuser', 'is_active']
class GroupAdmin(GroupAdmin):
list_display = ['name', persons]
list_display_links = ['name']
admin.site.unregister(User)
admin.site.unregister(Group)
admin.site.register(User, UserAdmin)
admin.site.register(Group, GroupAdmin)