Home > Enterprise >  Is there a clean way to lower the cyclomatic complexity of Django templates?
Is there a clean way to lower the cyclomatic complexity of Django templates?

Time:01-04

I have a Django template I'm working on that takes an object that has multiple properties and adds different tags based on those properties. For example if object.bold == True it adds the <b></b> tag, and if object.strikethrough == True it adds the <strike></strike> tag. I've seen some other posts that smell which suggest nesting the ifs like:

{% for object in objects %}
    {% if object.bold == True %}
        {% if object.strikethrough == True %}
            <b><strike>{{object.name}}</strike></b>
        {% else %}
            <b>{{object.name}}</b>
        {% endif %}
    {% else %}
        {% if object.strikethrough==True %}
            <strike>{{object.name}}</strike>
        {% else %}
            {{object.name}}
        {% endif %}
    {% endif %}
{% endfor %}

This code hurts me. I've also seen some wonky logic with only wrapping the beginning tags in if statements. Again, it's painful to introduce console errors.

Is there a better, cleaner way to achieve this result without nesting ifs? I'm leaning towards making a custom Django tag but that seems like overkill for something that I'm really hoping can be simpler.

CodePudding user response:

another possibility would be to just use css class e.g.

css-File:

.myboldTrue {
  font-weight: bold;
}

.mystrikethroughTrue {
  text-decoration: line-through;
}

html-File:

{% for object in objects %}
    <span > {{object.name}} </span>
{% endfor %}

CodePudding user response:

I ended up writing a custom decorator which worked out fairly well.

In myapp/templates/my_template.html I have something that looks like this:

{% load decorator_tags.py %}
{% for object in objects %}
    {% get_decorators object as result %}
    {{ result }}
{% endfor %}

Then in myapp/templatetags/get_decorators.py I have something that looks like this:

from django import template
from django.utils.safestring import mark_safe

register = template.Library()

@register.simple_tag(name='get_decorators')
def get_decorators(object):
    prepend_string = ''
    append_string = ''
    if object.bold:
        prepend_string = '<b>'   prepend_string
        append_string = append_string   '</b>'
    if object.strikethrough:
        prepend_string = '<strike>'   prepend_string
        append_string = append_string   '</strike>'
    
    return mark_safe(prepend_string   object.name   append_string)

Even though it's much more code, it feels cleaner, sticks to Django instead of using any fancy HTML or CSS, keeps my templates thin, and is reusable. I can probably clean up the get_decorators logic, but I can do that with minimal code changes now.

It took me a bit to work everything out, so I figured I post this here in case anyone else was running into the same issue.

  •  Tags:  
  • Related