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.
1 comment:
Great solution. THanks
Post a Comment