Reputation: 43
I feel like I have read about this a hundred times but I still can't figure out how to use permissions within a django-tables2 TemplateColumn
.
My goal is to be able to render buttons in a column based on permissions that a user may have or may not have on a given model. That does not sound complicated to me and from what I have read I should be able to use something like {% if perms.myapp.delete_mymodel %}
to achieve what I'd like to do.
Here is the code I'm trying to get to work as I expect:
import django_tables2 as tables
MY_MODEL_ACTIONS = """
{% if perms.myapp.change_mymodel %}
<a href="{% url 'myapp:my_model_edit' pk=record.pk %}" class="btn btn-sm btn-warning"><i class="fas fa-edit"></i></a>
{% endif %}
{% if perms.myapp.delete_mymodel %}
<a href="{% url 'myapp:my_model_delete' pk=record.pk %}" class="btn btn-sm btn-danger"><i class="fas fa-trash"></i></a>
{% endif %}
"""
class MyModelTable(tables.Table):
# some columns
actions = tables.TemplateColumn(
verbose_name="",
template_code=MY_MODEL_ACTIONS,
)
class Meta(BaseTable.Meta):
model = MyModel
fields = (
# some columns
"actions",
)
When rendering the table no issues are triggered but the column just do not display any buttons (yes I do have the permissions for them to show up). Removing the {% if … %}
clauses, thus removing the permission checks, allows the buttons to be seen of course.
Upvotes: 0
Views: 610
Reputation: 1
My solution is:
class MyModelTable(ColumnShiftTable):
delete = tables.LinkColumn("myapp:my_model_delete", text="delete", args=[
A("pk")], orderable=False)
class Meta:
model = MyModel
exclude = ("id",)
attrs = {
"class": "table table-responsive-sm table-bordered table-striped table-sm"
}
def before_render(self, request):
if request.user.has_perm('perms.myapp.delete_mymodel'):
self.columns.show('delete')
else:
self.columns.hide('delete')
# hide other columns
self.columns.hide('foo')
self.columns.hide('bar')
Upvotes: 0
Reputation: 4229
What adds perms
to your context?TemplateColumns
do not have the same context as the template {{ render_table table }}
is called from, so you must be a little more explicit.
The documentation for render_table
mentions it will attach the context of the calling template to table.context
, so this should fix your problem:
MY_MODEL_ACTIONS = """
{% if table.context.perms.myapp.change_mymodel %}
<a href="{% url 'myapp:my_model_edit' pk=record.pk %}" class="btn btn-sm btn-warning"><i class="fas fa-edit"></i></a>
{% endif %}
{% if table.context.perms.myapp.delete_mymodel %}
<a href="{% url 'myapp:my_model_delete' pk=record.pk %}" class="btn btn-sm btn-danger"><i class="fas fa-trash"></i></a>
{% endif %}
"""
Upvotes: 0
Reputation: 43
The issue was a bit tricky. I defined my own template to render the table and did not used the {% render_table table %}
tag inside it. Due to this the context was not reachable from the TemplateColumn
code.
To fix this, I changed my template a bit and move my table rendering custom code to another template file. After that I used the render_table
tag like this {% render_table table 'includes/table.html' %}
After this, the code that I mentioned above in the column works just fine, permissions are honored like expected.
Upvotes: 0