I have an application where I am using django-guardian
for object-level permission. In my ListView
, I am listing all my instances in a table. In each row, I need to show the edit button if the user has the permission to edit this object.
So, I doing something like:
{% extends "base.html" %}
{% load guardian_tags %}
{% block content %}
<table>
<thead>...</thead>
<tbody>
{% for i in items %}
<tr>
<td>{{ i.name }}</td>
<td>
{% get_obj_perms request.user for i as "i_perms" %} <!-- this one -->
{% if "change_item" in i_perms %}
<a href="{% url 'edit_item' i.id %}">Edit</a>
{% endif %}
</td>
</tr>
{% endif %}
</tbody>
</table>
{% endblock %}
Problem
Doing it that way is not optimized solution from database-wise. This solution makes a database query for each object to get the user permissions. How can I do so but with a single hit to the database to get all the objects' user permissions?
CodePudding user response:
I think you would need to use get_objects_for_user in your view and pass it in to your template via context, eg, in a function based view or as part of your get_extra_context() in a CBV
from guardian.shortcuts import get_objects_for_user
items = Item.objects.all()
permitted_items = get_objects_for_user(request.user, 'change_item', klass=items)
context['permitted_items'] = permitted_items
...
then in your template
{% for i in items %}
<tr>
<td>{{ i.name }}</td>
<td>
{% if i in permitted_items %}
<a href="{% url 'edit_item' i.id %}">Edit</a>
{% endif %}
</td>
</tr>
{% endfor %}