check for presence in queryset in DTL django - html

I am creating a to do list. I want to display the tasks if the user has any. If not, then display something else. I kept the design simple.
<h2>Here is the list of tasks! Start working!</h2>
{% if obj in task %}
<ul>
{% for obj in task %}
<li>{{ obj }}</li>
{% endfor %}
</ul>
{% else %}
<p>You dont have anything on this list yet!</p>
{% endif %}
The 'task' is the queryset and currently consists of 2 objects. But none of them are being displayed. Everything was working fine before I tried to apply the presence check. Now it just jumps to that else statement.
views.py:
def task(request):
task = Task.objects.filter(user=request.user)
queryset = task.order_by('-start_date')
context = {
'task': queryset,
}
return render(request, 'task-list.html', context)

Try in this way
<h2>Here is the list of tasks! Start working!</h2>
{% if task %}
<ul>
{% for obj in task %}
<li>{{ obj }}</li>
{% endfor %}
</ul>
{% else %}
<p>You dont have anything on this list yet!</p>
{% endif %}
Its {% if task %} not {% if obj in task %}
Hope this helps you, If anything please let me know

Related

Idiomatic way in Jekyll to inherit default data if project specific data unavailable

I am completely new to Jekyll. I did something like this:
{% assign top_nav = site.data.menus %}
{% if site.data.orgs[site.orgData].menus %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% endif %}
<ul>
{% for menu in top_nav %}
<li>
{{ menu.title }}
</li>
{% endfor %}
</ul>
Basically, I will grab an array of navigation items from a default folder. But if I notice the existence of a menu for a specific organization, then I will override the menu provided by the default folder.
What I don't like about this approach is I now have hundreds of places in my jekyll templates that does this if statement check. If this were any other scripting programming language, I would define a function like function($org_name,$prop) {return $site.data.orgs[$org_name][$prop] ? $site.data.orgs[$org_name][$prop] : $site.data[$prop]; } . What would be the idiomatic way to achieve the same objective in jekyll?
I tried a variation of David Jacquel's suggestion by doing this
./org_var.html
{% assign prop = include.prop %}
{% assign orgVar = site.data[prop] %}
{% if site.data.orgs[site.orgData][prop] %}
{% assign orgVar = site.data.orgs[site.orgData][prop] %}
{% endif %}
./_include/nav.html
{% include_relative ../org_var.html prop=menus %}
{% for menu in orgVar %}
... print menu items
./_layout/header.html
{% include_relative ../org_var prop='electronics.televisions' %}
{% for tv in orgVar%}
{{ tv.modelName }}
... print tv values
{% endfor %}
But I get a syntax error in ../org_var.html saying {% include_relative file.ext param='value' param2='value' %} . The documentation says I can't use relative path with include or include_relative. How do I make my org_var.html a reusable and global function? And will electronics.televisions even evaluate properly to the proper path of my site.data.org.[site.orgData][...path] variable?
Just realized there is a default: modifier for a variable like smarty templates.
{% assign top_nav = site.data.orgs[site.orgData].menus | default: site.data.menus %}
You can use Jekyll includes.
From anywhere you want to use your include :
{% include nav.html org_name=org_name prop=prop %}
Will call _include/nav.html that can be something like this :
{% assign org_name = include.org_name %}
{% assign prop = include.prop %}
{% if site.data.orgs[org_name][prop] %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% else %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% endif %}
<ul>
{% for menu in top_nav %}
...

Jekyll nested include with for loop

I'd like to use a {% for %} loop in an included file, to avoid repeating logic to create the loop array (it's an assign with multiple where_exps).
But I'd like to use different content depending on where I include the loop, so sometimes I will do this:
{% for i in a %}
<li>{{ i.name }}</li>
{% endfor %}
and sometimes:
{% for i in a %}
<loc>{{ i.url }}</loc>
{% endfor %}
How can I achieve this? So far I have to put each of the inner contents in their own template, so I would have files like below, but I'd like to avoid the extra template files, and just keep that content in the appropriate main file:
html_template.html:
<li>{{ i.name }}</li>
xml_template.xml:
<loc>{{ i.url }}</loc>
page_loop.html:
{% assign a = "logic I don't want to repeat" %}
{% for i in a %}
{% include {{ include.inner_template }} %}
{% endfor %}
html_main.html:
{% include page_loop.html inner_template="html_template.html" %}
xml_main.xml:
{% include page_loop.html inner_template="xml_template.xml" %}
It would probably be another more elegant (?) solution developing a plugin, but quickly modifying your code, in _includes/page_loop.html:
{% assign a = "something" %}
{% for i in a %}
{%if include.type == "name"%}
<li>{{ i.name }}</li>
{%else if include.type == "url"%}
<loc>{{ i.url }}</loc>
{%endif %}
{% endfor %}
Then each time you include page_loop.html pass an additional parameter specifying which type of output you want:
{% include page_loop.html type="name" %}
or
{% include page_loop.html type="url" %}

How can I loop on all items where a certain field is not empty?

I want to loop over all items in a collection that have a certain field set (not empty). I tried this:
{% assign papers_with_demos=site.data.papers | where:"demo", not blank %}
{% if papers_with_demos.size > 0 %}
<h2>demos</h2>
{% for paper in papers_with_demos %}]
...
{% endfor %}
{% endif %}
but it does not work; all papers are returned.
My goal is that the heading "demos" will be shown, only if there is one or more paper with a demo.
If papers are being returned, you must be using data files. If a value is empty for a particular key in a data file it will return false. So you could check the data key with a forloop like:
{% for paper in site.data.papers %}
{% if paper.demo %}
something
{% endif %}
{% endfor %}
You'll find more info in the Data Files section of the Jekyll documentation.
Updated in response to your reply:
{% for item in site.data.items %}
{% if item.random %}
{% assign random-val = item.random %}
{% if random-val %}
<p>true</p>
{% endif %}
{% endif %}
{% endfor %}
This will return true if inside items.yml, you have - random: true, nothing if empty.

What does capturing a liquid variable then assigning to nil do?

Jekyll bootstrap includes the file _includes/JB/setup:
{% capture jbcache %}
<!--
- Dynamically set liquid variables for working with URLs/paths
-->
{% if site.JB.setup.provider == "custom" %}
{% include custom/setup %}
{% else %}
{% if site.safe and site.JB.BASE_PATH and site.JB.BASE_PATH != '' %}
{% assign BASE_PATH = site.JB.BASE_PATH %}
{% assign HOME_PATH = site.JB.BASE_PATH %}
{% else %}
{% assign BASE_PATH = nil %}
{% assign HOME_PATH = "/" %}
{% endif %}
{% if site.JB.ASSET_PATH %}
{% assign ASSET_PATH = site.JB.ASSET_PATH %}
{% else %}
{% capture ASSET_PATH %}{{ BASE_PATH }}/assets/themes/{{ page.theme.name }}{% endcapture %}
{% endif %}
{% endif %}
{% endcapture %}{% assign jbcache = nil %}
I understand that this 1) captures the text as a variable then 2) assigns it to nil immediately, effectively throwing it away. So what does this do?
Because you want the side-effects of rendering but don't want the rendered output. If you don't capture, the rendered content is output. But you don't actually want the output, so you throw it away when you're done. It's a slight hack.
So if you want to compute without outputting the result, capturing in a variable is a reasonable thing to do. The "then assign to nil" hack is a way of saying we are interested in the side-effects of the rendering computation, not the output. Those other assignments persist have effects that persist even when the variable is thrown out.
The {%include custom/setup %}'s output will similarly be thrown away, but its side-effects may be important.

Check if an array is not empty in Jinja2

I need to check if the variable texts is defined or not in index.html.
If the variable is defined and not empty then I should render the loop. Otherwise, I want to show the error message {{error}}.
Basically this in PHP
if (isset($texts) && !empty($texts)) {
for () { ... }
}
else {
print $error;
}
index.html
{% for text in texts %}
<div>{{error}}</div>
<div class="post">
<div class="post-title">{{text.subject}}</div>
<pre class="post-content">{{text.content}}</pre>
</div>
{% endfor %}
How do I say this in jinja2?
I think your best bet is a combination of defined() check along with looking at the length of the array via length() function:
{% if texts is defined and texts|length > 0 %}
...
{% endif %}
To test for presence ("defined-ness"?), use is defined.
To test that a present list is not empty, use the list itself as the condition.
While it doesn't seem to apply to your example, this form of the emptiness check is useful if you need something other than a loop.
An artificial example might be
{% if (texts is defined) and texts %}
The first text is {{ texts[0] }}
{% else %}
Error!
{% endif %}
Take a look at the documentation of Jinja2 defined(): http://jinja.pocoo.org/docs/templates/#defined
{% if variable is defined %}
value of variable: {{ variable }}
{% else %}
variable is not defined
{% endif %}
Is it clear enough? In your case it could look like this:
{% if texts is defined %}
{% for text in texts %}
<div>{{ error }}</div>
<div class="post">
<div class="post-title">{{ text.subject }}</div>
<pre class="post-content">{{ text.content }}</pre>
</div>
{% endfor %}
{% else %}
Error!
{% endif %}
As mentioned in the documentation, you could also write:
{% for text in texts %}
<div class="post">
<div class="post-title">{{text.subject}}</div>
<pre class="post-content">{{text.content}}</pre>
</div>
{% else %}
<div>{{ error }}</div>
{% endfor %}
It handles both the case where texts is undefined, and the case where texts is empty.
This is a neat and simple solution that worked well for me!
{% if texts is defined and texts[0] is defined %}
...
{% endif %}
It's possible that texts could be defined but contain a single list element which is an empty string; For example:
texts = ['']
In this case, testing if texts is defined will produce a true result so you should test the first element instead:
{% if texts[0] != '' %}
..code here..
{% endif %}
You might also want to combine that with the |length filter to make sure it only has one element.
This worked for me when working with the UPS API where if there is only one object in a parent object the child is just an object, but when there is more than one child it's a array of objects.
{% if texts[0] %}
..code here..
{% endif %}
This is what worked for my use case in my Django app:
I needed to pass a queryset as context to an html template and display the block only if the queryset had values
Queryset:
events = Event.objects.filter(schedule_end__gte=date.today()).order_by('-created_at')
Passed context dictionary as follows:
{ "events" : events }
HTML template
{% if events %}
<h3>Upcoming Events</h3>
<ul>
{% for event in events %}
<li><h4>{{ event.title }}</h4></li>
{% endfor %}
</ul>
{% endif %}
This works for me ( But I make sure to return an empty array [] and not None if its empty )
{% if array %}
<table class="table">
...
</table>
{% endif %}
We can check if array is not empty by writing below jinja code.
where the content2 is an array defined under py file. #app.route("/<name>") def home(name): return render_template("index.html", content=name, content2=[])
{% if content2 %}
<div>
<h2>Array elements are available</h2>
{% for con2 in content2 %}
<p> {{con2}} </p>
{% endfor %}
</div>
{% endif %}
Thanks