How to remove spaces and empty lines from HTML in Django? - django

I use Python 3.4 + Django 1.7.1 with Eclipse - PyDev and I use AcroEdit to edit HTML.
I think AcroEdit uses two soft spaces for indent.
I made a custom template tag named custom_tag in custom_tag_library.py like:
# -*- coding: utf-8 -*-
from django import template
from _ast import Num
register = template.Library()
#register.inclusion_tag('custom_tag.html')
def custom_tag(content):
return {'content': content, 'children': content.children.all()}
and for custom_tag.html:
{% load custom_tag_library %}
<div class = 'a'>
{{ content.name }}
{% if children %}
<div class = 'b'>
{% for child in children %}
{% custom_tag child %}
{% endfor %}
</div>
{% endif %}
</div>
(As you can see, content object has name and children)
So, custom_tag is a recursive tag gives a tree structure represented in <div> hierarchy.
But when I use this, the output HTML has many spaces and empty lines like this:
I tried {% spaceless %} {% endspaceless %}, but it doesn't work.
I think this appears because I use indents to increase readability for my codes. But I want to maintain my coding style about the indentation.
How can I fix this?

I've got exactly the same problem. You want to have clean template html files, that you can easily read (what you got), and you want at the same time to have human readable html when you render it.
So you won't be happy with the solution of changing your templatetag.html file to something like this, which looks like old php spaghetti :
{% load custom_tag_library %}
<div class = 'a'>{{ content.name }}
{% if children %}<div class = 'b'>
{% for child in children %}{% custom_tag child %}{% if not forloop.last %}
{% endif %}{% endfor %}
</div>{% endif %}
</div>
The second solution (and also the best one) is to have a middleware to read and rewrite every HttpResponse to something more tidy.
You can find exactly what you want on the PyEvolve website. What it does is basically :
Parse your HttpResponse html with BeautifulSoup
Prettify it (with cool indent)
Return it as the new HttpResponse
But with this solution, you might have performence issue.

Related

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

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.
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 class="mybold{{ object.bold }} mystriketrough{{ object.strikethrough }}"> {{object.name}} </span>
{% endfor %}
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.

Get a random object of a Wagtail page model but not the current one

So I have this template context processor:
from cases.models import CasePage
def random_case(request):
case = CasePage.objects.live().order_by('?')
return {'random_case': case}
And in the template I do this:
{% for entry in random_case %}
{% if request.get_full_path != entry.get_url %}
{% if forloop.first %}
<a class="ajax-link project-next" href="{{ entry.get_url }}">
<div class="nav-project-title">{{ entry.title }}</div>
<div class="nav-title">next</div>
</a>
{% endif %}
{% endif %}
{% endfor %}
And this works but the problem is sometimes the object is the same as the page so nothing is displayed. It would be great if that one would be skipped in favour of the next entry. And it's also too much logic in the template for me. What would be the best way to move this logic into the context processor and make it work?
Make random_case a method of CasePage, and filter out the case with an ID equal to self.
class CasePage(Page):
# ...
def random_case(self):
return CasePage.objects.live().exclude(id=self.id).order_by('?').first()
You can then refer to this method within your template as page.random_case - bear in mind that a new random choice will be made on each call, so you probably want something like {% with page.random_case as case %}.

Why can't I use this django template variable in conditions?

Following the advice here, I have access to the allowed_contributors variable in the template and I can print it out, but using it in any kind of if-else statement doesn't work. It doesn't give me a 500 error, but it acts like it's empty.
The file I'm loading from templatetags:
from django import template
from django.conf import settings
register = template.Library()
#register.simple_tag
def allowed_contributors():
return getattr(settings, "ALLOWED_CONTRIBUTORS", "")
Here's what I've put in the template (not showing the "load" command at the top, but I guess that must be working).
<div class="container">
<h1>Create new project</h1>
<p> {% allowed_contributors %} </p>
{% if "true" in allowed_contributors %}
<p>"true" found in allowed_contributors!</p>
{% endif %}
{% if "false" in allowed_contributors %}
<p>"false" found in allowed_contributors!</p>
{% endif %}
</div>
The HTML output looks like:
<div class="container">
<h1>Create new project</h1>
<p> ('auth', 'false') </p>
</div>
I've tried outputting the allowed_contributors multiple times in case it's being consumed the first time, but it seems to make no difference.
Do I need to reference it in a different way when I'm using it as a condition for an if statement?
If it helps I'm using Django 1.8
EDIT: Neither of the sensible answers provided worked for me, probably due to some other config on this project that I'm not aware of. I've worked around it by using the slightly more involved context_processor solution.
The same code works for me.
Note: <p> {% allowed_contributors %} </p> needs to be <p> {{ allowed_contributors }} </p>
Maybe that's throwing off your code?
I see
Create new project
('auth', 'false')
"false" found in allowed_contributors!
{% allowed_contributors %}
This does not set a value in the context, it just outputs the result of the tag.
To assign the value, do
{% allowed_contributors as contributors %}
Then you can display the value,
{{ contributors }}
and use it in other tags:
{% if "true" in contributors %}
<p>"true" found</p>
{% endif %}
In Django 1.8 and earlier, you can't do {% allowed_contributors as contributors %}
with the simple_tag decorator. You need to use assignment_tag instead.
#register.assignment_tag
def allowed_contributors():
return getattr(settings, "ALLOWED_CONTRIBUTORS", "")

Why is this django template tag failing to display?

I have a template tag located in catalog/templatetags/catalog_tags.py, which looks like this:
register = template.Library()
#register.inclusion_tag("tags/navigation.html")
def nav_links():
flatpage_list = FlatPage.objects.all()
return {'flatpage_list': flatpage_list }
I have a catalog.html which has {% load catalog_tags %}, to load that tag, and is followed by an inclusion tag for my navigation, {% include "tags/navigation.html" %}.
navigation.html contains the following:
{% with flatpage_list as pages %}
{% for page in pages %}
{{ page.title }}
{% endfor %}
{% endwith %}
But the list of flat_pages is not appearing in my navigation section. Why is that?
If I understand right, with your current state you have something liek this in catalog.html template:
{% load catalog_tags %}
.....
{% include "tags/navigation.html" %}
What this code does, is just renders the "tags/navigation.html" template, nothing more. So your custom template tag is not hit at all. To fix it, you should replace include with nav_links:
{% load catalog_tags %}
.....
{% nav_links %}
See Django docs for reference.
Not sure if it's just a copy paste error or not but return {'flatpage_list': flatpage_list isn't closed properly return {'flatpage_list': flatpage_list}
Also could this be something more suited for a context processor?
EDIT: After reading the other answer, I realized what you are trying to do, when you were using the {% include ... %} tag it seemed like you just wanted to populate the flatpage_list

Handcoding forms vs django forms

Are there any performance differences between handcoding forms in django (as well as all the validations in the views.py) and using django's form library? If they are roughly the same, in which scenarios would one handcode a form over using the built-in ones?
Also, What about handcoding the HTML templates and using the django block tags, etc. to re-use certain areas?
Do you have insane, zero-tolerance performance requirements? As in: will people actually die or come to harm or you be fired if a page takes an extra few milliseconds to render?
I doubt it, so just let the framework do the lifting up to the point where you need more control over the HTML output -- that's actually far more likely a scenario than you needing to avoid executing some Python to save (at an utter guess) 15ms.
When you do need more control, that's when it's best to splice in some handmade HTML, or - even better - create an include/partial for form fields that you can reuse everywhere, to save you the time of manually writing more than you need to, but still giving you a lot more flexibility than myform.as_p etc
Here's a rough snippet I use and adapt a lot, to give me lots of control over form fields and also let me leverage the Django templating framework to save me time:
In my template:
{% for form_field in myform %}
{% include "path/to/partials/form_field_as_p.html" %}
{% endfor %}
And in that form_field_as_p.html, something like:
{% if not form_field.is_hidden %}
<p>
{% if form_field.errors %}
{% for error in form_field.errors %}
<span class="errorlist">{{error}}</span>
{% endfor %}
{% endif %}
{{ form_field.label_tag }}
{% if form_field.field.required %}
<span class="required">*</span>
{% endif %}
{{ form_field }}
{% if form_field.help_text %}
<span class="form-help-text">{{ form_field.help_text }}</span>
{% endif %}
</p>
{% else %}
<div>{{ form_field }}</div> {# hidden field #}
{% endif %}