Home > Blockchain >  How to determine if a template block is empty/blank in Django?
How to determine if a template block is empty/blank in Django?

Time:04-01

I am using Django templates for my website, and I have a template block for the webpage's title: I have a base template (base.html), which formulates the <title> element like this:

<title>{% block title %}{%endblock %} - Website Title</title>

And then, in each page template, I put a block like so:

{% block title %}Webpage Name Here, e.g. About Us{% endblock %}

which would then give me: <title>Webpage Name Here, e.g. About Us - Website Title</title>

Is there a way to determine programmatically, within the base template, the size/length/content of the title block? I want to make it so that on my homepage, there is no "-" in the title, it just says "Website Title". I figure the best way would be to do something similar to this:

<title>{% block title %}{% end block %}{% if title|length > 0} - {/if}Website Title</title>

... but I can't figure out for the life of me how to determine the length of the {% block title %} which is being passed from the page template.

CodePudding user response:

Based on my understanding of the documentation, the block tag cannot be assigned to a variable (at least I couldn't figure out a workaround) and the value cannot be reused elsewhere in the page. This is probably because of how the template inheritance model treats it:

This limitation exists because a block tag works in “both” directions. That is, a block tag doesn’t just provide a hole to fill – it also defines the content that fills the hole in the parent.

However, it is possible to achieve your desired results with the {% filter %} block, since it filters the contents inside the block and doesn't specifically require a variable.There is a clean way and a sort-of hacky way to handle this.


Clean way: Define a custom filter

Following the steps at Writing custom template filters, write a suffix filter that only concatenates the string when the value is not empty.

# filename: suffix.py
from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def suffix(value, args):
    return value   str(args) if value else value

@stringfilter forces value to be a coerced into a string first, so '' should be the only falsy value. But since this is in a python file, you can just use a more-suited condition if necessary.

Now this can be loaded in base.html as follows (the argument after load has to be the previous filename):

{% load suffix %}
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{% filter suffix:' -' %}{% block title %}{% endblock title %}{% endfilter %} Website Title</title>
    </head>

    <body>
        {% block content %}{% endblock content %}
    </body>
</html>

Now if the child HTML file overrides the block like {% block title %}About Us{% endblock title %}, you will get About Us - Website Title. If it doesn't include that block, you get Website Title.

Note: I haven't fully checked the details around safe strings and auto-escaping since both the parameters to the filter are picked by the developer. Please check out the additional details in the docs if you plan to use this filter with more complicated input or with user input.


Hacky but easy way: Use default and add filters

This method uses built-in filters and documented behavior, but it isn't very readable/intuitive so I would avoid using it. Just replace the <title> tag with

<title>{% filter default:0|add:' -' %}{% block title %}{% endblock title %}{% endfilter %} Website Title</title>

This relies on the following behavior by add, emphasis mine:

This filter will first try to coerce both values to integers. If this fails, it’ll attempt to add the values together anyway. This will work on some data types (strings, list, etc.) and fail on others. If it fails, the result will be an empty string.

The issue I was having is that using just add would always put a dash (even in the empty case), while join treats strings as a list, so inserts a dash between every character. But if the default value is not a string, it fails since ' -' cannot be coerced into an integer (it doesn't convert 0 to '0', so int str won't work).

The results are the same as the first method, a non-empty block will not trigger default and result in About Us - Website Title, while an empty block stays empty to result in Website Title.

  • Related