Diego Quirós
Diego Quirós

Reputation: 977

Django template not recognizing getattr

I´m want to display dinamically a table in a html template. In the view I have:

def get_object( request ):
    objects = MyObject.objects.all()
    return render(request, 'table.html', { 'myObjects':objects, 'fields':ObjectAdmin.list_display})

then in 'table.html'

<thead class="tables-success"> 
        <tr>
            {% for field in fields %}
                <th>{{ field }}</th>
            {% endfor %}            
        </tr>    
    </thead>
        {% for row in myObjects %}
            <tr>
                {% for field in fields %}
                <td>{{ getattr(row, field) }}</td>
                    <!--<td>{{ row|getattr:field }}</td>-->
                {% endfor %}
            </tr>
        {% endfor %}

and in admin.py

class MyObjectAdmin(admin.ModelAdmin):
    list_display = [ 'name']#
    list_per_page = 8
    search_fields = [ 'name']
admin.site.register(  Object, MyObjectAdmin )

but I m receiving the below error:

Could not parse the remainder: '(row, field)' from 'getattr(row, field)'

or

Exception Value:    Invalid filter: 'getattr'

if I use

{{ row|getattr:field }}

Upvotes: 2

Views: 172

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476493

Django's template language does not allow calling any method (with parenthesis, so that means any method with a parameter). As for the template filters, you can only use builtin ones [Django-doc], or the ones you register.

A lot of people therefore make a custom template filter and register that one. But often that is not a good idea: there is a reason why this is not made possible: it is to prevent from writing business logic in the templates.

One can simply pre-process the data in the template:

def get_object(request):
    objects = [
        [getattr(item, field) for field in ObjectAdmin.list_display]
        for item in MyObject.objects.all()
    ]
    return render(
        request,
        'table.html',
        {'myObjects': objects, 'fields': ObjectAdmin.list_display},
    )

and then render this in the template with:

<thead class="tables-success"> 
    <tr>
        {% for field in fields %}
            <th>{{ field }}</th>
        {% endfor %}            
    </tr>    
</thead>
<tbody>
    {% for row in myObjects %}
        <tr>
            {% for item in row %}
                <td>{{ item }}</td>
            {% endfor %}
        </tr>
    {% endfor %}
</tbody>

that being said, there are already a lot of libraries that do what you aim to achieve, like django-tables2 [readthedocs.io]. Using the list_display is also a bit of a risk, since a ModelAdmin allows to add functions to the list_display, or methods defined in the ModelAdmin itself, hence it is not said that these are the names of attributes on the objects.

Upvotes: 1

Related Questions