﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
18763	Shortcut to get users by permission	Sergiy Kuzmenko	Nick Pope	"In my apps I often need to get the list of users who have a specific permission. But it seems there is no shortcut to do this in Django itself (unless I'm missing something obvious). And getting users by permission is slightly more complicated than may appear at first sight because user permission can be set at user level or at group level, and also we need to pay special attention to superusers.

So I usually end up doing something like this:

{{{
from django.contrib.auth.models import User
from django.db.models import Q

def get_users_by_permission_q(permission_name, include_superusers=True):
    """""" Returns the Q object suitable for querying users by permission. If include_superusers
    is true (default) all superusers will be also included. Otherwise
    only users with explicitely set permissions will be included. """"""
    (appname, codename) = permission_name.split(""."")
    
    query = \
        Q(user_permissions__codename=codename, user_permissions__content_type__app_label=appname) | \
        Q(groups__permissions__codename=codename, groups__permissions__content_type__app_label=appname)    
    
    if include_superusers:
        query |= Q(is_superuser=True)
    
    # The above query may return multiple instances of User objects if user
    # has overlapping permissions. Hence we are using a nested query by unique
    # user ids.
    return {'pk__in': User.objects.filter(query).distinct().values('pk')}

def get_users_by_permission(permission_name, include_superusers=True):
    """""" Returns the queryset of User objects with the given permission. Permission name
    is in the form appname.permission similar to the format
    required by django.contrib.auth.decorators.permission_required
    """"""
    return User.objects.filter( get_users_by_permission_q(permission_name, include_superusers) )
}}}

And them in my models.py: 

{{{
class MyModel:
    my_fk_field = models.ForeignKey(User, limit_choices_to=dict(is_active=True, \
        *get_users_by_permission_q(""myapp.change_my_model"", False)))
}}}

Or in my views:
{{{
users = get_users_by_permission(""myapp.change_my_model"")
}}}

It would be nice to have something like this in django/contrib/auth/utils.py

If this proposal gets accepted I can contribute a patch.
"	New feature	closed	contrib.auth	dev	Normal	fixed		Sergiy Kuzmenko pelletier berker.peksag@…	Ready for checkin	1	0	0	0	0	0
