4

Using djang-tables2 custom table as:

tables.py:

import django_tables2 as tables
from django_tables2.utils import A
from .models import Person

class PersonTable(tables.Table):

    view_column = tables.LinkColumn('person:pessoas_detail', args=[A('pk')])

    class Meta:
        model = Person

views.py:

from .models import Person

class ListView(SingleTableView):
    model = Person
    table_class = PersonTable

I need to check permission FOO on the view_column. Because, view_column is a class attribute, I cannot use a decorator as @permission_required.

Probably I could call something other than tables.LinkColumn to test the permission and then return the column. However, in order to do this, I would need to access the user object (probably from the request object), which I wouldn't have access at this point.

Is there a simpler way for doing this?

Basically the idea is to show a column only if there is permission access to it or not show at all.

rsd
  • 67
  • 1
  • 9

2 Answers2

6

I think that the easier way to do what you want is to simply use a template column (that's what I do):

view_column = tables.TemplateColumn("""
  {% if has_perm('FOO') %}
    <a href='{% url "person:pessoas_detail" record.id %}>{{ record.id }}</a>
  {% else %}
    {{ record.id }}
  {% endif %}
""", orderable=False)

Now if the user has the correct permission then it will display the link - if not it will just display the id of each record.

Serafeim
  • 14,962
  • 14
  • 91
  • 133
  • This has 2 downsides as I can see. The column is not optional. I know it was not asked for, but it is what you get if the permissions were checked before returning the Column object. It also seems to be a great performance penalty. – rsd Aug 08 '16 at 12:37
  • I am starting to think this might be the only solution. Django caches the execution code, so I dont know if it can be trusted that the next request will be for the same user. django-tables2 uses the __new__ method to collect information about the columns which also gives less room for a class attribute manipulation. – rsd Aug 08 '16 at 14:29
  • As I said, I'm using this solution in similar cases. There's no performance penalty if you use pagination to the table (i.e render less than 100 rows for each page). There are other solutions but you'll then probably need to manipulate the table in the view (or define two tables one with the view_column and one without it and render the correct one depending on permissions -- not DRY). – Serafeim Aug 08 '16 at 14:56
1

Try before_render function.

    Example::
        class Table(tables.Table):
            name = tables.Column(orderable=False)
            country = tables.Column(orderable=False)
            def before_render(self, request):
                if request.user.has_perm('foo.delete_bar'):
                    self.columns.hide('country')
                else:
                    self.columns.show('country')
Binoy Mathew
  • 123
  • 1
  • 2
  • 7