Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove line breaks from Django template

I have a loop in a template like this

{% spaceless %}
{% for lang_code, lang_name in LANGUAGES %}
    <link hreflang={{ lang_code }} href="http://example.com/
    {% if lang_code|length > 2 %}
        {{ some_path }}
    {% else %}
        {{ other_path }}
    {% endif %}
    ">
{% endfor %}
{% endspaceless %}

Which produces something like this

<link hreflang="en-gb" href="http://example.com/
    some_path/ 
    "><link hreflang="de" ...>

Is it possible to re-write this code so that the whole tag is written in one line like so?

<link hreflang="en-gb" href="http://example.com/some_path/">
<link hreflang="de" href="http://example.com/other_path/">
...

P.S. This can be achieved if the if/else clause is stretched over one line, but then the line becomes unreadable.

like image 856
abudis Avatar asked Nov 02 '15 13:11

abudis


2 Answers

I needed the same, because I'm using a template to generate an email subject line (non-HTML, so {% spaceless %} is useless). In my case, the template had taken on lots of different cases, and everything had to be written in a single line over about 500 characters.

So in the spirit of {% spaceless %}, I wrote my own {% linebreakless %}:

import six
from django import template
from django.template.base import Node
from django.utils.functional import allow_lazy


register = template.Library()


@register.tag
def linebreakless(parser, token):
    nodelist = parser.parse(('endlinebreakless',))
    parser.delete_first_token()
    return LinebreaklessNode(nodelist)


class LinebreaklessNode(Node):
    def __init__(self, nodelist):
        self.nodelist = nodelist

    def render(self, context):
        strip_line_breaks = allow_lazy(lambda x: x.replace('\n', ''), six.text_type)
        return strip_line_breaks(self.nodelist.render(context).strip())

Please note that it (intentionally!) preserves all whitespace except line breaks.

An example usage for an email template would look like this, assuming the above is loaded in a template tag module called linebreakless.py:

{% load linebreakless %}{% linebreakless %}

{# Email subjects are (encoded) text, not HTML, so we don't need any autoescaping! #}
{% autoescape off %}

New Notification
 •
{% if flag %}
 about this
{% else %}
 about that
{% endif %}
!

{% endautoescape %}
{% endlinebreakless %}

Note that the {% linebreakless %} tag has to be on the first line (and after the {% load %} directives) to prevent any line breaks in the generated file.

like image 66
Henrik Heimbuerger Avatar answered Oct 03 '22 06:10

Henrik Heimbuerger


I needed it and updated @Henrik 's answer to work with keep_lazy

 @register.tag
 def linebreakless(parser, token):
     nodelist = parser.parse(('endlinebreakless',))
     parser.delete_first_token()
     return LinebreaklessNode(nodelist)


 class LinebreaklessNode(Node):
     def __init__(self, nodelist):
         self.nodelist = nodelist

     def render(self, context):
         strip_line_breaks = keep_lazy(six.text_type)(lambda x: x.replace('\n\n', '\n'))

         return strip_line_breaks(self.nodelist.render(context).strip())
like image 36
eugene Avatar answered Oct 03 '22 07:10

eugene