< / >

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.