Home > front end >  Show only not None values in Django template
Show only not None values in Django template

Time:01-15

I have a Model with numerous attributes; in the template rendered by my DetailView I want to show only the attributes that are not None.

This can be easily done with an if template tag that checks if the value of the attribute is not None, tho I should add an if condition for every attribute in my model, and there's a lot of them.

I would like to iterate through all the attributes and if not None display them. In pseudo code it would look like this:

{% for attribute in my_instance.all_attributes %}
  {% if attribute.value is not None %}
    {{attribute.value}}

I can get a tuple of concrete attributes both through the class or the instance:

cls._meta.concrete_fields

or

self._meta.concrete_fields

Now that I have the my_instance.all_attributes in my pseudo code example, I can iterate it but I don't know how to get the actual value of the instance's attribute.

EDIT:

.concrete_values returns an array of Field instances, it looks like this:

(<django.db.models.fields.BooleanField: gov>, <django.db.models.fields.BooleanField: in_group>, <django.db.models.fields.CharField: legal_class>,)

I can access the value of the name attribute of the Field instance using .name. Calling .name on the example above would return 'gov', 'in_group', 'legal_class'

CodePudding user response:

The authors of Django went out of their way to make sure that the template language isn't used to do things like this! Their opinion as I understand it is that templates should do formatting, and Python should do program logic.

There are two ways around it. One is to create a structure that the template can iterate through, and pass it to the DetailView context. Something like

def get_context_data(self):
    data = super().get_context_data(**kwargs)

    fieldnames = [
        x.name for x in self.object._meta.concrete_fields ]
    display_fields = [
        (name, getattr( self.object, name, None)) for name in fieldnames ]
    display_fields = [ x for x in display_fields if x[1] is not None ]

    data['display_fields'] = display_fields
    return data

and in the template you can now do

{% for name,value in display_fields %} 

You might prefer to code a list of names instead of using ._meta.concrete_fields because that lets you choose the order in which they appear. Or you could start with an ordered list and append anything that's in the _meta but not yet in your list (and delete anything that's in your list but not in _meta)

The other way is to use Jinja as the template engine for this view.

  •  Tags:  
  • Related