Reputation: 11098
I want to get a queryset along with their group membership to avoid expensive additional database hits and to make managing stuff in the template much easier.
Initially I tried to prefetch the groups a user belongs to:
def get_queryset(self):
User.objects.filter(is_active=True).prefetch_related('groups')
But then it makes it difficult to show and hide things in the template based on the groups:
{{ user.groups.all }}
gives
<QuerySet [<Group: Managers>]>
Then I though perhaps an annotation may be better with a is_manager
and is_head
eg:
from django.db.models import BooleanField, Case, Value, When
def get_queryset(self):
'''Return both active and inactive users for managers
Annotate with is_manager = True/False
'''
query = When(groups__name__in=[MANAGER_GROUP_NAME, ], then=Value(1))
return self.model.objects.all().annotate(
is_manager=Case(
query,
default=Value(0),
output_field=BooleanField()
)
)
Which worked okay but gave me an error:
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'my_site.auth_group.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
But would be easy to use in the template with:
{% if user.is_manager %} Manager {% else %} Normal user {% endif %}
Is there an easier way to do it?
Edit:
The final query:
self.model.objects.prefetch_related('groups').all().annotate(
is_manager=Case(
When(
groups__id__exact=1, then=True
), default=False, output_field=BooleanField()
)
).values("pk", "id", "email", "is_manager")
Upvotes: 2
Views: 289
Reputation: 6040
Nice attempt with your approach.
Firstly, if possible consider using group ids instead of group names to identify managers
. Will dramatically improve query performance and spelling related bugs.
Following is a quick snippet that I tried and is working for me. (on postgres).
User.objects.prefetch_related("groups").annotate(
is_super=Case(
When(
groups__id__in=[1, 2,3 ], then=1
), default=0, output_field=IntegerField()
)
).order_by("id").values_list("id", "username", "is_super")
Upvotes: 1