The problem is that it's unable to use model _meta in templates. You can achive the same using an example verbose_name_tags.py templatetag.
# verbose_name_tags.py from django import template register = template.Library() def get_field_verbose_name(instance, arg): return instance._meta.get_field(arg).verbose_name register.filter('field_verbose_name', get_field_verbose_name) def get_queryset_field_verbose_name(queryset, arg): return queryset.model._meta.get_field(arg).verbose_name register.filter('queryset_field_verbose_name', get_queryset_field_verbose_name)
you can get your header names rendered the DRY way.
Assuming your model looks like this:
class Product(models.Model): name = models.CharField(_(u"Name"), max_length=20) weight = models.PositiveIntegerField(_(u"Weight"))
Your template would be similar to the one below:
{% load verbose_name_tags %} <table> <thead> <tr> <th>{{ object_list|queryset_field_verbose_name:"name" }}</th> <th>{{ object_list|queryset_field_verbose_name:"weight" }}</th> </tr> </thead> <tbody> {% for product in object_list %} <tr> <td>{{ product.name }}</td> <td>{{ product.weight }}</td> </tr> {% endfor %} </table>
What if you need sorting ?
For some time I've been using a django-sorting for sorting my tabular data.
The new code
{% load sorting_tags %} {% autosort object_list %} <table> <thead> <tr> {# _("Name").. need to specify the display name all the time.. bad.. #} <th>{% autosort 'name' _("Name") %}</th> <th>{% autosort 'weight' _("Weight") %}</th> </th></tr> </thead> <tbody> {% for product in object_list %} <tr> <td>{{ product.name }}</td> <td>{{ product.weight }}</td> </tr> {% endfor %} </tbody> </table>
Great, but this is not DRY! You can do this the other way. Note: I think {% autosort %} should take verbose_name by default (maybe will take a look into the code later, but for now we can achieve the same using a {% with %} and verbose_name_tags.py template tags.
{% load sorting_tags %} {% load verbose_name_tags %} {% autosort object_list %} {% endfor %} <table> <thead> <tr> {% with name=object_list|queryset_field_verbose_name:"name" %} <th>{% autosort 'name' name%}</th> {% endwith %} {% with weight=object_list|queryset_field_verbose_name:"weight" %} <th>{% autosort 'weight' weight %}</th> {% endwith %} </tr> </thead> <tbody> <tr> <td>{{ product.name }}</td> <td>{{ product.weight }}</td> </tr> </tbody> </table>
Now we can just change verbose_name in models.py and we don't have to worry about the table headers.
You can also use a "field_verbose_name" for model instances:
{# assuming {{ product }} is an instance of Product model #} {% load verbose_name_tags %} {{ product|field_verbose_name:"name" }}: {{ product.name }}
Some might wonder why didn't I simply use one templatetag name which would identify if it checks for queryset or instance field. I decided to use different names to quickly see If I act with querysets or instances. Hope you like it.