work around setting variables in django templates - django

I have this code that I used from twig to display sections according to the same date.
I'm trying to use the same code in Django but I can't set variables in its template system. What is the sane way to do this? The correct way? How do people tackle such a problem?
{% set date = "prout" %}
{% for article in articles %}
{% if article.date != date %}
{% if date != "prout" %}
</ul>
</section>
{% endif %}
{% set date = article.date %}
<section class="row">
<h2>{{ article.date }}</h2>
<ul>
<li>+ {{ article.titre }}</li>
{% else %}
<li>+ {{ article.titre }}</li>
{% endif %}
{% endfor %}
</ul>
</section>

The closer concept to 'set' variables is with tag. Quoting Built-in template tags and filters django docs:
with
Caches a complex variable under a simpler name. This is useful
when accessing an “expensive” method (e.g., one that hits the
database) multiple times.
For example:
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}

Related

How to display django-treebeard MP in template as dropdown menu?

Following the treebeard docs api example, I created an annotated_list of my tree using get_annotated_list(parent=None, max_depth=None) with parent=<my root node>. I pass this to my template and using the example they attribute in the docs to Alexey Kinyov, I am able to successfully display my tree using
{% for item, info in annotated_list %}
{% if info.open %}
<ul><li>
{% else %}
</li><li>
{% endif %}
{{ item }}
{% for close in info.close %}
</li></ul>
{% endfor %}
{% endfor %}
What I would like though is to be able to give these nested lists dropdown features. Borrowing from this standard example on w3schools, I modified it to work with my annotated_list template variable and ended up with this:
<ul id="myUL">
<li><span class="caret">{{ annotated_list.0.0 }}</span>
{% for item, info in annotated_list|slice:"1:" %}
{% if info.open %}
<ul class="nested"><li>
{% else %}
</li><li>{% if item.get_children_count > 0 %}<span class="caret">
{% endif %}
{% endif %}
{{ item }}
{% if item.get_children_count > 0 %}</span>
{% endif %}
{% for close in info.close %}
</li></ul>
{% endfor %}
{% endfor %}
</li>
</ul>
My code almost works, but does not seem to display node children for left-most nodes and I can't figure out why.
Note: CSS & JS not included in question but needed to make the dropdown menu work (I'm just using the out-of-the-box CSS/JS used in that w3schools example)
The most likely reason is that there is a problem with the tree.
Run Model.find_problems() to confirm.
Model.fix_tree() can fix most of the common problems.
Note that the get_annotated_list_qs() function doesn't really work at all.
You can try this Code:
<ul id="myUL">
{% for item, info in annotated_list %}
{% if item.get_children_count > 0 %}
<li><span class="box">{{item}}</span><ul class="nested">
{% else %}
<li>{{item}}</li>
{% endif %}
{% for close in info.close %}
</ul>
{% endfor %}
{% endfor %}
</ul>
It worked for me.
To add some missing context:
views.py:
def tree(request):
annotated_list = Category.get_annotated_list()
# template_name = 'JsonDefine/tree.html'
context = {
'annotated_list': annotated_list
}
return render(request, 'JsonDefine/tree3.html',context)
urls.py
from django.urls import path
from . import views
app_name = 'MyApp'
urlpatterns = [
path('tree/', views.tree, name='tree'),
]

Django template within a for loop

I have a for loop that looks like this:
<ul>
{% for post in latest_post_list %}
<li>{{ post }}</li>
</ul>
{% empty %}
<p>No posts are available.</p>
{% endfor %}
But I want to wrap each post object in a template, so for example:
{% for post in latest_post_list %}
{% include 'jobposttemplate.html' %}
{% empty %}
{% include 'noposts.html' %}
{% endfor %}
jobposttemplate.html will then include all the various information held within the JobPost model.
I tried:
{% for jobposttemplate.html in latest_post_list %}
{{ jobposttemplate.html }}
{% empty %}
{% include 'noposts.html' %}
{% endfor %}
But, predictably, it didn't work. Basically I'm just trying to avoid having to having to write the html out each time, e.g.:
{% for post in latest_post_list %}
<div style="blah">{{ post.deadline }}
</div>
<div style="schmah">{{ post.created_at }}
</div>
{% empty %}
<p>No posts are available.</p>
{% endfor %}
If you are using app specific subfolders inside your templates/ directory, you need to add them to the file name here too.
{% include 'myapp/jobposttemplate.html' %}
And if you want the template to have access to variables, you can add them to the template's scope using with. The sub-template also has access to all scope variables too.
{% include 'myapp/jobposttemplate.html' with object=post %}

django tables how to detect if table is empty

I am new to django and web development and based on examples and help on SO, I have pieced together something which takes a model and renders it in a django-table. My template code is basically as follows:
{% block content %}
{% load static %}
{% load render_table from django_tables2 %}
<div class="function-page">
<div class="table-form">
<div class="function-container">
{% render_table reviews %}
</div>
</div>
</div>
{% endblock %}
The view is as follows:
#login_required(login_url="login/")
def review(request):
table = DummyTable(DummyModel.objects.all())
form = DummyForm()
RequestConfig(request, paginate={"per_page": 10}).configure(table)
return render(request, 'review.html', {'reviews': table, 'DummyForm': form})
This works fine. However, what I would like to do is show a message to the user saying that there are no records when the database table is empty. In the current setting, it shows an empty table with the columns which is probably not the best from a usability point of view.
There are two options. Either you set empty_text inside class Meta
class Reviews(tables.Table):
class Meta:
empty_text = _("There are no reviews yet")
Or you can check it inside the template and avoid rendering table this way
{% if reviews_table.data.list %}
{% render_table reviews_table %}
{% else %}
<h1>There are no reviews yet</h1>
{% endif %}
Probably the easiest way is in your template. Assuming your variable that's empty is called reviews:
{% block content %}
{% load static %}
{% if reviews %}
{% load render_table from django_tables2 %}
<div class="function-page">
<div class="table-form">
<div class="function-container">
{% render_table reviews %}
</div>
</div>
</div>
{% else %}
<span> Whatever holding response/error message you want. </span>
{% endif %}
{% endblock %}
Per this this answer, for example, using {% if variable %} against a valid but empty variable, it generally evaluates to False, letting you use the {% if reviews %}.
However, if you need a really bulletproof check, you can do {{ value|default:"nothing" }} - from here.
You could also do it in your views, and pass an error message back to the template using the standard Messages framework included in Django:
from django.contrib import messages
messages.add_message(request, messages.INFO, "No reviews found, I'm afraid!.")
You need to include something like this in your templates to use messages:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
Or you could do both! :)
test against table.paginated_rows it will be empty and evaluated to False when the table have no data.
they use this in django_tables2/templates/django_tables2/bootstrap.html:~26 template:
{% for row in table.paginated_rows %}
...
{% empty %}
... {{ table.empty_text }}
{% endfor %}
Do this:
{% if reviews %}
<div class="function-page">
<div class="table-form">
<div class="function-container">
{% render_table reviews %}
</div>
</div>
</div>
{% else %}
<div>
<p> Message to use </p>
</div>
{% endif %}
Milano answer worked to me, but removing ".list" from the if conditional:
{% if reviews_table.data.list %}
{% render_table reviews_table %}
{% else %}
<h1>There are no reviews yet</h1>
{% endif %}

Django template: check for empty query set

Is there a way to check for an empty query set in the Django template? In the example below, I only want the NOTES header to be displayed if there are notes.
If I put an {% empty %} inside the "for" then it does display whatever is inside the empty tag, so it knows it's empty.
I'm hoping for something that does not involve running the query twice.
{% if notes - want something here that works %}
NOTES:
{% for note in notes %}
{{note.text}}
{% endfor %}
{% endif %}
Clarification: the above example "if notes" does not work - it still displays the header even with an empty query set.
Here's a simplified version of the view
sql = "select * from app_notes, app_trips where"
notes = trip_notes.objects.raw(sql,(user_id,))
return render_to_response(template, {"notes":notes},context_instance=RequestContext(request))
Edit: the view select selects from multiple tables.
Have a look at the {% empty %} tag.
Example from the documentation
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% empty %}
<li>Sorry, no athletes in this list.</li>
{% endfor %}
</ul>
Link: https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#for-empty
If you are interested in a table, or some kind of heading if there are results, add the forloop.first:
{% for athlete in athlete_list %}
{% if forloop.first %}
Athlete Name:
{% endif %}
{{ athlete.name }}
{% empty %}
Sorry, no athletes in this list.
{% endfor %}
Try {% if notes.all %}. It works for me.
In your view check whether notes is empty or not. If it is then you pass None instead:
{"notes": None}
In your template you use {% if notes %} as normal.
It's unfortunate that you're stuck using a raw query set - they're missing a lot of useful behavior.
You could convert the raw query set into a list in the view:
notes_as_list = list(notes)
return render_to_response(template, {"notes":notes_as_list},context_instance=RequestContext(request))
Then check it as a boolean in the template:
{% if notes %}
Header
{% for note in notes %}
{{ note.text }}
{% endfor %}
{% endif %}
You could also make it happen without conversions using forloop.first:
{% for note in notes %}
{% if forloop.first %}
Header
{% endif %}
{{ note.text }}
{% endfor %}
What about:
{% if notes != None %}
{% if notes %}
NOTES:
{% for note in notes %}
{{ note.text }}
{% endfor %}
{% endif %}
{% else %}
NO NOTES AT ALL
{% endif %}
Your original solution
{% if notes %}
Header
{% for note in notes %}
{{ note.text }}
{% endfor %}
{% endif %}
Works now with Django 1.7 and thanks to QuerySet caching, it does not cost and extra query.
Often the right way to do this is to use the {% with ... %} tag. This caches the query so it runs only once and also gives you more flexibility with your markup than using {% empty %}.
{% with notes as my_notes %}
{% if my_notes %}
<ul>
{% for note in my_notes %}
<li>{{ note }}</li>
{% endfor %}
</ul>
{% else %}
<p>Sorry, no notes available</p>
{% endif %}
{% endwith %}
With this particular example I'm not sure how useful it is but if you're querying Many-to-Many field, for instance, it's likely what you want to do.
Use {% empty %} in django templates
{% if list_data %}
{% for data in list_data %}
{{ data.field_1 }}
{% endfor %}
{% else %}
<p>No data found!</p>
{% endif %}
We can write above code with {% empty %}.
{% for data in list_data %}
{{ data.field_1 }}
{% empty %}
<p>No data found!</p>
{% endfor %}

Django, loop over all form errors

At my template, I want to iterate through all form errors, including the ones that are NOT belonging to a specific field. ( which means for form.errors, it should also display for __all__ errors aswell)
I have tried several versions, Ie:
<div id="msg">
{% if form.errors %}
<div class="error">
<p><span>ERROR</span></p>
<ul>
{% for key,value in form.errors %}
{% for error in value %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
</div>
Still no achievement, I will be greatful for any suggestion.
Form errors in Django are implemented as an ErrorDict instance (which is just a subclass of dict with extras). Try a slight adjustment to your template for loop syntax:
{% for key, value in form.errors.items %}
Are you, by any chance, looking for form.non_field_errors? That is how you would get access to the errors that aren't associated with a particular field.
{% if form.non_field_errors %}
<ul>
{{ form.non_field_errors.as_ul }}
</ul>
{% endif %}
Check the forms.py test suite as well for another example. Search for form.non_field_errors