Malcoolm
Malcoolm

Reputation: 478

Using django permissions in template tags

I'm currently checking permissions in my templates to decide whether or not I want to display a particular link.

This works very well for my base.html that is extending in my normal templates:

base.html

{% if perms.myapp.can_add %}
    #display link
{% endif %}

my template

{% extends "riskass/base.html" %}
{% block content %}
    # do stuff #
{% endblock %}

BUT i also use template tags for repetitive items in the template, and the same permission checks doesn't seem to work in them.

Does anybody have an idea of what I might be doing wrong ? Thanks !

my template

{% extends "riskass/base.html" %}

{% load show_items %}

{% block content %}
    # do stuff #
    {% show_items items_list%}
{% endblock %}

templatetags/show_items.py

from django import template

register = template.Library()

@register.inclusion_tag('myapp/show_items.html')
def show_items(items):
    return {'items': items}

myapp/show_items.html

{% for item in items%}

    # display stuff: this works
    ...

    # check permissions: 
     {% if perms.myapp.can_add %}
        #display other link: doesn't do anything
     {% endif %}

Upvotes: 2

Views: 1818

Answers (1)

little_birdie
little_birdie

Reputation: 5867

perms is part of the template context in which your template "my template" is being rendered. But your inclusion tag template myapp/show_item.html by default has its own context and won't inherit perms or any other template variables unless you arrange for that by passing takes_context=True in your tag registration, as well as doing just a bit of code to pass some or all of that context into your tag template context.

There's an example of this in the Django docs:

https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/#inclusion-tags

It's a bit confusing because the docs seem to imply that you can either pass your own arguments to the tag method or pass context, but not both. However that is not the case. When takes_context=True is passed to @register.inclusion_tag(), the effect will be that django passes context as the first argument to your tag function, followed by any arguments you wish to pass to your tag. The context being passed is that of the template where your tag is located.. so you can then take what you need from there and pass it to the included template, eg:

@register.inclusion_tag('riskass/show_ratings.html', takes_context=True)
def show_ratings(context, ratings):
    return {
        'ratings': ratings,
        'perms': context.get('perms', None)
    }

The tag usage would then look like this:

{% show_ratings ratings_list %}

There is some useful info in this other Stack Overflow question and answer, although it is not exactly the same as your question you might want to take a look:

Pass a context variable through an inclusion tag

Upvotes: 2

Related Questions