Problem:

You want to display some information in a database record in Django, but you also want to display the field’s verbbose name.  In other words, you want to display “What is your favorite Color?” instead of the field name, “favorite_color” or the slightly better “Favorite Color”.  This can be a particular problem if you have very cryptic field names for some reason or another.

The problem is that in Django the “pretty label” information can be defined in the Model’s fields as “verbose_name” or possibly in a related Form as “label”.  In my case I was using ModelForms to make life easier. ModelForms, among other things, take the “verbose_name” values from your Models and stuff it into the Form’s fields “label” values.  You could just create a ModelForm based on your Model, and then fetch the label, but the Label is not defined in the Form if a verbose_name was not defined for the model.  This grabs the pretty label if it exists, and falls back to the field name if its undefined.  This problem is also discussed on Stack Overflow as:.

Django – Iterate over model instance field names and values in template

I’ve provided this solution there as well.

Solution:

There should really be a built-in way to do this. I wrote this utility build_pretty_data_view that takes a model object and form instance (a form based on your model) and returns a SortedDict.

Benefits to this solution include:

  • It preserves order using Django’s built-in SortedDict.
  • When tries to get the label/verbose_name, but falls back to the field name if one is not defined.
  • It will also optionally take an exclude() list of field names to exclude certain fields.
  • If your form class includes a Meta: exclude(), but you still want to return the values, then add those fields to the optional append() list.

To use this solution, first add this file/function somewhere, then import it into your views.py.

utils.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
from django.utils.datastructures import SortedDict

def build_pretty_data_view(form_instance, model_object, exclude=(), append=()):
    i=0
    sd=SortedDict()

    for j in append:
        try:
            sdvalue={'label':j.capitalize(),
                     'fieldvalue':model_object.__getattribute__(j)}
            sd.insert(i, j, sdvalue)
            i+=1
        except(AttributeError):
            pass

    for k,v in form_instance.fields.items():
        sdvalue={'label':"", 'fieldvalue':""}
        if not exclude.__contains__(k):
            if v.label is not None:
                sdvalue = {'label':v.label,
                           'fieldvalue': model_object.__getattribute__(k)}
            else:
                sdvalue = {'label':k,
                           'fieldvalue': model_object.__getattribute__(k)}
            sd.insert(i, k, sdvalue)
            i+=1
    return sd

So now in your views.py you might do something like this

from django.shortcuts import render_to_response
from django.template import RequestContext
from utils import build_pretty_data_view
from models import Blog
from forms import BlogForm
.
.
def my_view(request):
   b=Blog.objects.get(pk=1)
   bf=BlogForm(instance=b)
   data=build_pretty_data_view(form_instance=bf, model_object=b,
                        exclude=('number_of_comments', 'number_of_likes'),
                        append=('user',))

   return render_to_response('my-template.html',
                          RequestContext(request,
                                         {'data':data,}))

Now in your my-template.html template you can iterate over the data like so…

{% for field,value in data.items %}

    <p>{{ field }} : {{value.label}}: {{value.fieldvalue}}</p>

{% endfor %}

Good Luck. Hope this helps someone!

Solution