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

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", "")

Related

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 %}.

Wagtail customizing struct block template on admin

I have read the 'custom-editing-interfaces-for-structblock' section of documentation. Then I have written:
settings = StructBlock([
('width', blocks.CharBlock(required=False, max_length=20 ) ),
('background_color', blocks.CharBlock(max_length=10, required=False))
], form_template = 'personal_web/admin_blocks/section_settings.html' )
I have copied the code in wagtail/admin/templates/wagtailadmin/block_forms/struct.html to my custom struct template for better customizing.
--- my section_settings.html ---
<div class="{{ classname }}">
{% if help_text %}
<div class="object-help help">{{ help_text }}</div>
{% endif %}
<ul class="fields">
{% for child in children.values %}
<li{% if child.block.required %} class="required"{% endif %}>
{% if child.block.label %}
<label{% if child.id_for_label %} for="{{ child.id_for_label }}"{% endif %}>{{ child.block.label }}:</label>
{% endif %}
{{ child.render_form }}
</li>
{% endfor %}
</ul>
</div>
On the admin there is an error:
'builtin_function_or_method' object is not iterable... In template /Users/burakk/BurakWorks/Web/VIRTUAL_ENVIRONMENTS/python3.6.1_dj_1_11/lib/python3.6/site-packages/wagtail/wagtailadmin/templates/wagtailadmin/block_forms/sequence_member.html, error at line 23
By the way I am using jinja as template renderer, django 1.11.6, python 3.6
I checked to see if this was an jinja2 issue I have changed the children.values properties children.values() etc...
Now on the admin I see all the elements as 'html string' not the actual input fields...
Thanks
I think this might be happening because your section_settings.html template is inside the location normally used for jinja2 templates - probably some_app/jinja2/personal_web/admin_blocks/section_settings.html (if you're using the configuration shown at http://docs.wagtail.io/en/v1.13.1/advanced_topics/jinja2.html) - and ends up being interpreted as a Jinja2 template. Mixing Jinja2 and Django templates in this way is untested, and likely to fail in unpredictable ways (such as the HTML being double-escaped, as you're seeing).
Try moving it to some_app/templates/personal_web/admin_blocks/section_settings.html, with the template changed back to Django syntax (children.values() changed back to children.values, etc).

How to remove spaces and empty lines from HTML in 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.

How to add top save button on django admin change list?

I want to have a save button on top of django admin change list page. It seems that django don't have this functionality built-in. The save_on_top option only controls behavior on change form page. Any suggestion is welcome.
In Django 3 (and maybe earlier, not sure) in your custom admin form add save_on_top = True
class MyAdmin(admin.ModelAdmin):
save_on_top = True
First, you need a way to extend the template found at django/contrib/admin/templates/admin/change_list.html. If you don't already know how to do that, check out this answer and this answer.
Next, you need to create your own change_list.html template and put code similar to the following in it. For the sake of simplicity, I've included inline CSS. However, this is bad practice, so you should not do it. Assuming you move the CSS to an external file, you won't need to load admin_static. Lastly, the extends line that you use might not be exactly the same as what I've shown here.
{% extends "contrib/admin/templates/admin/change_list.html" %}
{% load i18n admin_static %}
{% block result_list %}
{% if cl.formset and cl.result_count %}
<div style="border-bottom: 1px solid #ccc; background: white url({% static "admin/img/nav-bg.gif" %}) 0 180% repeat-x; overflow: hidden;">
<p>
<input type="submit" name="_save" class="default" value="{% trans 'Save' %}"/>
</p>
</div>
{% endif %}
{{ block.super }}
{% endblock %}
The {% if %} tag and the <input> tag inside of it is from django/contrib/admin/templates/admin/pagination.html.
The CSS is based on the CSS for #changelist .paginator and is found in django/contrib/admin/static/admin/css/changelists.css.
If you don't mind having pagination links at the top of the page as well, you can do it with a few lines of template code, worksforme in Django 2.0.
Create my_app/templates/admin/my_app/my_model/change_list.html:
{% extends "admin/change_list.html" %}
{% load admin_list %}
{% block result_list %}
{% pagination cl %}
{{ block.super }}
{% endblock %}
This will render the pagination and the save button:
Could benefit from a line or two of CSS, though...

Django template if statement always evaluates to true

This seems like it should be pretty straightforward, but for some reason I am unable to solve this problem. I'm using Django 1.4. I am trying to do a basic check to see if a list QuerySet is empty or not during template rendering, but the if statement I'm using seems always to evaluate to true.
I have a Django template that reads:
{% extends 'includes/base.html' %}
{% if object_list %}
...
{% block data %}
{% for object in object_list %}
...
{{ object.create_date }}
...
{% endfor %}
{% endblock data %}
...
{% endif %}
'base.html' has the block:
<body>
{% block content %}
...
<div class="row-fluid">
<div class="span12">
{% block data %}
<div align="center"><i>No data.</i></div>
{% endblock data %}
</div><!-- span12 -->
</div><!-- row -->
{% endblock content %}
...
</body>
The view function generating the QuerySet is here:
def barcode_track(request, model):
query = request.GET.get('barcode_search', '')
object_list = model.objects.all()
if query:
object_list = model.objects.filter(barcode__icontains=query)
return render_to_response('barcode_track/barcode_list.html',
{'object_list': object_list, 'query': query},
context_instance=RequestContext(request))
Which is called via this form:
<form id="barcode_search_form" method="get" action="" class="form">
<input type="text" name="barcode_search" value="{{ query }}" />
<button type="submit" class="btn">Search</button>
</form>
And the urls.py line:
urlpatterns = patterns('barcode_track.views',
url(r'^$', 'barcode_track', {'model': Barcode},
name="barcode_track"),)
The idea is that results will only be presented if they exist in object_list, and otherwise the parent block will remain unaltered. I have tried changing the name of object_list, and I have printed {{ dicts }} to the page to ensure that object_list is, in fact, empty (which it is). I am not using a generic view, although I realize that the name suggests as much. I have actually had this trouble in a different app I wrote using similar logic, so I must be doing something systematically incorrectly.
What am I missing here?
You can't wrap control flow tags like if around a block. Your problem is that the child template's definition for block data is being used simply because it's there.
You can fix it by placing the if tag inside block data. If you want to inherit the parent's contents when the list is empty, add an else case that expands to {{ block.super }}.