Comments not working in jinja2 - python

I have a template(test.html) as follows:
{% extends 'base.html' %}
{% from "_formhelpers.html" import render_field %}
{% block content %}
<div class="container">
<div class="row">
<div class="span6 offset3">
<form class="form-horizontal" action="/create_user/" method="post">
{{ form.csrf_token }}
<dl>
{{ render_field(form.name) }}
{{ render_field(form.members) }}
<!--<div class="control-group">
<label class="control-label">
{{ form.task.label }}
</label>
<div class='controls'>
{{ form.task}}
{% if form.task.errors %}
<ul class="text-error">
{% for error in form.task.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>-->
</dl>
</form>
</div>
</div>
</div>
{% endblock %}
When rendering this template using Flask's render_template("test.html", form=form). I got following error "UndefinedError: 'tickapp.forms.TeamForm object' has no attribute 'task'".
As you can see I have commented out 'form.task' in the template(whole ) and also there is no such field in models and in my form.
I wonder why jinja2 is considering commented html content. I trusted comments(!) and spent couple of hours on this issue. Finally, deleted all the comments and it started working.Anybody working in jinja2 faced this problem? and do you know why it is happening?

Basically, jinja2 is only concerned with finding an evaluating its own blocks, not the structure of the HTML. If you want to exclude a section of your template entirely, you can use jinja2's comment syntax:
{# This is a comment now.
<div class="control-group">
...
</div>
#}

Related

Difficulties with having a Flask-wtforms in the main layout template of the website

I have been working on a website for the past while using flask, python and bootstrap. I added footer to my website and I would like a "contact me" form in the footer. Below is my current code for creating a contact form and displaying this form.
class ContactForm(FlaskForm):
email = StringField("", validators=[DataRequired(), Email()])
content = TextAreaField("", validators=[DataRequired(), length(min=2, max=500)])
submit = SubmitField("Submit")
<form method="POST" action="">
<div class="form-group">
{{ form.email.label(class="form-control-label") }}
{% if form.email.errors %}
{{ form.email(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.email(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.content.label(class="form-control-label") }}
{% if form.content.errors %}
{{ form.content(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.content.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.content(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
I created this footer in my "layout.html" file which is the base file that all other html documents extend from so that all pages will have this same footer.
The issue is that then I need to create and instance of this form object on every page of my application and handle the validate_on_submit on every page. (Sample code below)
#app.route("/random_page", methods=["GET", "POST"])
def random_page():
form = ContactForm()
if form.validate_on_submit():
# code to send the email goes here
return render_template("random_page")
I am looking for an easier way to do this so that I don't need to repeat code on every page and so that It can be considerably simpler. I am not very experienced with flask and would highly appreciate the help.
Use the #app.context_processor decorator, documentation to inject an instance of your contact form into the template context for all templates. For example:
#app.context_processor
def inject():
return dict(
contact_form=ContactForm(),
)
Then re-write the form's HTML to use the contact_form template variable, also adding in an appropriate action route.
<form method="POST" action="{{url_for('contact')}}">
<div class="form-group">
{{ contact_form.email.label(class="form-control-label") }}
{% if contact_form.email.errors %}
{{ contact_form.email(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ contact_form.email(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ contact_form.content.label(class="form-control-label") }}
{% if contact_form.content.errors %}
{{ contact_form.content(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in contact_form.content.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ contact_form.content(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ contact_form.submit(class="btn btn-outline-info") }}
</div>
</form>
Then add a route to solely handle this form's postback:
#app.route("/contact", methods=["POST"])
def contact():
form = ContactForm()
if form.validate_on_submit():
# code to send the email goes here
# blah blah

Trying to reverse posts from newer on top but I keep getting errors in Flask

Here is the code I'm trying to run in my Flask App
{% extends "bootstrap/base.html" %}
{% block title %}Testing title{% endblock %}
{% block content %}
<div class="container">
<h1>Posts</h1>
<h3>Postings</h3>
<form action="/" method="post">
<input hidden placeholder="Name" name="name">
<input placeholder="Post whatever you want..." name="post" required>
<button class="btn btn-primary" type="submit" value="Submit">Submit</button>
</form>
{% for post in posts reversed %}
<div>
{{ 'Anonymous' + ': ' + post[2] }}
</div>
{% endfor %}
</div>
{% endblock %}
This is the error I get jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'reversed'
Figure reversed would work since I found some examples online that does that
The correct syntax in Jinja2 to loop through a list in reverse order is:
{% for post in posts|reverse %}
{{ post }}
{% endfor %}

Variable inside a forloop in Python Django

am new to Python and Django.
I have a problem. i want to increment the value of current inside the for loop and check if the value is equal to 1 and if not i want to display some HTML tags.
here is my code.
{% with current=1 %}
{% for howitwork in howitworks%}
{% if current != 1 %}
<div class=item>
<div class=container-fluid>
<div class=row>
<div class="col-md-5 rex-block">
<img src="media/{{ howitwork.image }}" alt>
</div>
<div class="col-md-7 rx-services-box">
<div class=rx-conta-title>
<h3>{{ howitwork.subtitle }}</h3>
</div>
<p>{{ howitwork.description|linebreaks }}</p>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
{% endwith %}
I don't see any errors but its not working.
If you need to skip the logic on first loop iteration just use forloop.first field. It is accessible inside forloop block.
{% for howitwork in howitworks %}
{% if not forloop.first %}
<!-- do stuff -->
{% endfor %}
Use forloop.counter (forloop.counter0 for 0-indexed) instead of current variable.
Here is the possible solution for your snippet:
{% for howitwork in howitworks%}
{{forloop.counter}}
{% if forloop.counter != 1 %}
<div class=item>
<div class=container-fluid>
<div class=row>
<div class="col-md-5 rex-block">
<img src="media/{{ howitwork.image }}" alt>
</div>
<div class="col-md-7 rx-services-box">
<div class=rx-conta-title>
<h3>{{ howitwork.subtitle }}</h3>
</div>
<p>{{ howitwork.description|linebreaks }}</p>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
To check the current iteration count, you can use {{forloop.counter}}
So your condition could be like this
{% if forloop.counter == 1 %}
<!-- Do things -->
{% else %}
<!-- Do some other things -->
{% endif %}

Django For Loop Execution Issue

I have a django for loop that is supposed to add items inside a form element. However, when the code executes, django just puts the first element inside the form and puts the following element outside the form html tag.
The code is:
<form action="." method="post" class="basket_summary" id="basket_formset">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{% with line=form.instance product=form.instance.product %}
{% purchase_info_for_line request line as session %}
<div class="row no-margin cart-item">
{{ form.id }}
<div class="col-xs-12 col-sm-2 no-margin">
{% with image=product.primary_image %}
{% thumbnail image.original "100x100" upscale=True as thumb %}
<a href="{{ product.get_absolute_url }}" class="thumb-holder">
<img class="lazy" alt="" src="{{ thumb.url }}" />
</a>
{% endthumbnail %}
{% endwith %}
</div> <!-- /.thumbnail holder -->
<div class="col-xs-12 col-sm-5 ">
<div class="title">
{{ line.description }}
</div>
{% trans "Update" %}
{% if user.is_authenticated %}
| {% trans "Save for later" %}
{% endif %}
<div style="display:none">
{{ form.save_for_later }}
{{ form.DELETE }}
</div>
{% for field_errors in form.errors.values %}
{% for error in field_errors %}
<span class="error-block"><i class="icon-exclamation-sign"></i> {{ error }}</span>
{% endfor %}
{% endfor %}
</div> <!-- /.Title holder -->
<div class="col-xs-12 col-sm-3 no-margin">
<div class="quantity">
<div class="le-quantity">
<form>
<a class="minus" href="#reduce"></a>
<input name="form-0-quantity" id="id_form-0-quantity" readonly="readonly" type="text" value="{{ form.quantity.value }}" />
<a class="plus" href="#add"></a>
</form>
</div>
</div>
</div><!-- /.Quantity Holder -->
<div class="col-xs-12 col-sm-2 no-margin">
<div class="price">
{% if line.is_tax_known %}
{{ line.unit_price_incl_tax|currency:line.price_currency }}
{% else %}
{{ line.unit_price_excl_tax|currency:line.price_currency }}
{% endif %}
</div>
</div> <!-- /.Price Holder -->
</div><!-- /.cart-item -->
{% endwith %}
{% endfor %}</form>
What I expect is that django should have multiple <div class="row no-margin cart-item"> items in the form tag but that isn't happening.
How do I fix this?
Looks like you are missing closing form tag </form> at the end.
EDIT: as others mentioned in comments it could be because you have forms inside form. This will result in unpredictable behavior.

Checking if authenticated in Django template inheritance

I have the following code in a template and am having difficulty showing when a user is logged in. I will be able to login, but when I revisit the page, it shows that I'm still not authenticated.
{% extends "base.html" %}
{% load catalog_tags %}
{% block site_wrapper %}
<div id = "main">
Skip to main content
<div id = "banner">
<div class="bannerIEPadder">
<div class="cart_box">
{% cart_box request %}
</div>
</div>
</div>
<div style="float:right;">[search box goes here]</div>
<div id="navigation">
<div class="navIEPadder">
<!--navigation tabs at the top of each page -->
{% comment %}{% include "tags/navigation.html" %} {% endcomment %}
{% category_list request.path %}
</div>
</div>
<div id="middle">
<div id="sidebar">
<!--<div class="sidebarIEPadder">[search box goes here]</br>
{% comment %}{% category_list request.path %}{% endcomment %}
</div>-->
</div>
<div id="content">
<!-- <a name = "content"></a>-->
<div class="contentIEPadder">
{% block content %}{% endblock %}
</div>
</div>
</div>
<div id="footer">
<div class="footerIEPadder">
{% footer_links %}
</div>
</div>
</div>
{% endblock %}
And here's the file it references. Since this will be an extension of all templates, is there something I need to consider?
###category_list.html
<!--<h3>Categories</h3>-->
<!--<ul id="categories">-->
<ul>
{% with active_categories as cats %}
{% for c in cats %}
<li>
{% comment %}
{% ifequal c.get_absolute_url request_path %}
{{c.name}}
{% else %}
{% endcomment %}
<div>{{c.name}}</div>
{% comment %}{% endifequal %}{% endcomment %}
</li>
{% endfor %}
<div class="fr">
<ul>
<li>
{% if user.is_authenticated %}
Logout
{% else %}
Login
{% endif %}
</li>
</div>
{% endwith %}
</ul>
<div class="cb"></div>
Am I missing something here?
You need to pass a RequestContext to the template. The easiest way to do this is to import django.shortcuts and use the render method in your view:
return render(request, "my_template.html")
Is django.contrib.auth.context_processors.auth in your TEMPLATE_CONTEXT_PROCESSORS setting.py?
Do you use requestContext rendering template?
Check that sessions are enabled: MIDDLEWARE_CLASSES should contains 'django.contrib.sessions.middleware.SessionMiddleware'

Categories

Resources