< / >

This is a blog by about coding and web development.

Field labels in templates

Posted on in

There’s no way in Django (that I’ve found) to render a field’s name in a template. This means you end up with <th>Field Name</th> all over your templates. Why hello there, DRY violation!

The fields are stored in model._meta.fields, but templates don’t allow you to access variables which start with an underscore. I’ve got two little utility functions I wrote for myself to generate a dict of labels I can use in my templates:

    def get_labels_for(model, cap=True, esc=True):
        from django.template.defaultfilters import capfirst
        from django.utils.html import escape
        labels = {}
        for field in model._meta.fields:
            label = field.verbose_name
            if cap:
                label = capfirst(label)
            if esc:
                label = escape(label)
            labels[field.name] = label
        return labels

    def with_labels(context, cap=True, esc=True):
        from django.db.models import Model
        result = context.copy()
        for k, v in context.iteritems():
            if isinstance(v, Model):
                result[k + '_labels'] = get_labels_for(v, cap, esc)
            elif hasattr(v, '__getitem__') and len(v) > 0:
                if isinstance(v[0], Model):
                    result[k + '_labels'] = get_labels_for(v[0], cap, esc)
        return result

The parameters:

  • model can be a model class or a model instance.
  • If cap is True, the first letter of each label will be capitalized.
  • If esc is True, the labels will be escaped for HTML.

So, in your view:

    def some_view(request, foo_id):
        foo = get_object_or_404(Foo, id=foo_id)
        context = {'foo': foo, 'foo_labels': get_labels_for(foo)}
        return render_to_response('foo.html', context)

And in your template:

    {{ foo_labels.bar }}: {{ foo.bar }}

with_labels works the same way, except you can just surround your context with it:

    def some_view(request, foo_id):
        foo = get_object_or_404(Foo, id=foo_id)
        bars = Bars.objects.all()
        context = {'foo': foo, 'bars': bars}
        return render_to_response('foo.html', with_labels(context))

It will detect the models and lists of models in the context and add foo_labels and bars_labels to the context.