How to iterate over list of fields and display verbose_name and value in HTML template ?

Hello.

I want to dynamically iterate over pre-selected object’s fields and in HTML template display verbose name and value.
I did that by:

  • creating custom template tags to get verbose name and value of object’s field
  • defining which fields to show (show_fields) in view and passing this information as context
  • calling defined custom template tags in HTML template for list of fields

Please see the code below.

I would like to hear from you if there is a better approach to do this ?

Thanks!

# templatetags.py
@register.filter
def field_verbose_name(my_object, field_name):
    return my_object._meta.get_field(field_name).verbose_name
@register.filter
def field_value(my_object, field_name):
    object_field = my_object._meta.get_field(fieldname)
    display_value = my_object._get_FIELD_display(object_field) # _get_FIELD_display() covers also TextChoices
    if display_value == True: # covers BooleanField > True
        return "Yes"
    elif display_value == False: # covers BooleanField > False
        return "No"
    elif display_value == None: # covers None
        return "-"
    return display_value

# views.py
def product_detail(request):
    product_object = ... # get object
    show_fields = ["name", "description", "price"]
    context = {'product_object': product_object, 'show_fields': show_fields}
    return render(request, 'my_template.html', context)

# my_template.html
{% for fieldname in show_fields %}
        {{ product_object|field_verbose_name:fieldname }} = {{ product_object|field_value:fieldname }} <br>
{% endfor %}

EDITED: updated field_value to use _get_FIELD_display() instead of getattr(). This way nice display will be done also for TextChoices. Additionally, “translate” True/False/None into Yes/No/-.

A ModelForm with read-only fields (or a widget that just renders the value) might be clearer to understand? The field would then do the verbose name for you.

But otherwise, nothing else comes to mind except listing the fields explicitly in the template

My first reaction to this is that you really don’t want to do this in the template - you’re a lot better off preparing the context directly and minimizing the amount of work done by the rendering engine.

Then I realized that this functionality looks a lot like what the Django admin does, and so I checked it out to see how it does this - and my guess was correct. The admin does all the work in the view, minimizing the effort in the template.

My suggestion would be to create a utility function to build the data to be rendered and call that in the view. It’s going to perform a lot better that way.

How can I retrieve the verbose_name and corresponding value of each field in a list dynamically within an HTML template?

@Colterzamir - That’s not where you want to do that work. You want that preparation to be done in the view or as a set of model methods to be called as references in the variable tag.

As mentioned by others, this may not be the best approach. It is better to do that in view and then pass it to HTML template via context.
But if you still want to do it from templates, my example in initial post works good !

I’m new to Django, and I’m trying to understand why this should be done in the view.

Is it just because of the performance benefit, since the render() code has to parse the template language to figure out what is needed?

In my use-case, I have a side-panel template that is included by a bunch of other templates, so it looks like I’ll have to add code to a bunch of views to populate the context with what I want. If the template language had code to query the models directly, then I could get by with a lot less code.

It’s partly that, but more than just that. It’s also a general “Best-practice” for Django. The DTL is specifically designed with limitations to encourage work be done in Python and not in the templates.

This is a topic that has been discussed a few times here in the past. The most recent thread that I can find is Django design philosophies DTL - confirm if should update

Nope, Django provides facilities for that.

If this is something appearing in multiple views, then you can use a custom context processor to make it available on every page.

This is commonly for things like menus or dynamically generated headers or footers on a page.

It’s also used for other purposes like making specific variables always available, like the currently logged-in user.

Since the context processor receives the request object as a parameter, it can also be customized to provide different values based on the URL or other attributes in the request.

See the docs page starting with The Django template language: for Python programmers | Django documentation | Django for details and examples.

Finally, if you really have unique requirements, you also have the ability to create new tags and filters to cover cases that just can’t be handled any other way.

Thanks Ken. I took a quick look at custom context processors, and that does look exactly like what I need.

Thanks.

Found this method that retrieves all fields from an instance.

Doing this on the view:

fields = model._meta.get_fields()
field_data = [(field.verbose_name, getattr(self.object, field.name)) for field in fields]
context['fields'] = field_data

and calling this on the template:

   {% for field in fields %}
        <li>
            {{field.0}} -- {{field.1}}
        </li>
   {% endfor %}

shows all the fields (verbose_name, value) of a given model instance. Hope it helps!