djangodjango-guardian

Get all objects' django guardian permissions of the authenticated user in template


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?


Solution

  • 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 %}