I'm making my first steps with flask and also jinja2. I have run through some examples but now i try to integrate flask-security and got stuck a bit.
I try to built a modal with an login-form, so I put up a div like this:
<div class="modal">
<h3>Login</h3>
<form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.email) }}
{{ render_field_with_errors(login_user_form.password) }}
{{ render_field_with_errors(login_user_form.remember) }}
{{ render_field(login_user_form.next) }}
{{ render_field(login_user_form.submit) }}
</form>
That is the template code taken from the example provided by flask-security. Now i tried to wrap that in
{% extends layout.html %}
{% block loginModal %} ... {% endblock %}
and tried to invoke that in the layout.html by
{% block loginModal %}{% endblock %}
which now i learned is not the way, as the content is rendered and the layout.html only invoked.
Now i tried to put that code directly in the layout.html once by the include statement and as this didn't work i put it in directly.
I also added
{% from "security/_macros.html" import render_field_with_errors, render_field %}
in the first line, which are macros provided by the flask-security package. but all i get is the error:
UndefinedError: 'login_user_form' is undefined (after a long traceback)
I'm totally stuck here, reading jinja2 docs on the website for about an hour now. How can i get this form to work?
Update (I'm sorry, it is a late update):
My layout.html which implements the base layout for all pages
<!doctype html>
<html>
<head>
<title>MyExample</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/gumby.css') }}">
</head>
<body>
<div class=page>
<nav id="navbar-main-nav" class="navbar">
<div class="row">
<a class="toggle" gumby-trigger="#navbar-main-nav #main-nav" href="#"><i class="icon-menu"></i></a>
<h1 class="four columns logo">Logo</h1>
<nav class="five columns pull_right">
<ul id="main-nav">
<li><span>Link1 </span></li>
<li><span>Link2</span><i class="icon-cog" title="Customize"></i></li>
{% if current_user.is_authenticated() %}
<li>Hello {{ current_user.name }}</li>
<li>Logout</li>
{% else %}
<li>Open Modal</li>
<li>Register</li>
{% endif %}
</ul>
</nav>
</div>
</nav>
<div class="modal" id="modal1">
<div class="content">
<a class="close switch" gumby-trigger="|#modal1"><i class="icon-cancel" /></i></a>
<div class="row">
<div class="ten columns centered">
<div class="row">
<div class="five columns">
{% block loginModal %}{% endblock %}
</div>
<div class="five columns">
<!-- register Form -->
</div>
</div>
</div>
</div>
</div>
</div>
{% block body %}{% endblock %}
</div>
<script src="{{ url_for('static', filename='js/libs/modernizr-2.6.2.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/jquery-2.0.2.min.js') }}"></script>
<script gumby-touch="js/libs/" src="{{ url_for('static', filename='js/libs/gumby.min.js') }}"></script>
</body>
</html>
My login.html
{% extends layout.html %}
{% block loginModal %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% include "security/_messages.html" %}
<h3>Login</h3>
<form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.email) }}
{{ render_field_with_errors(login_user_form.password) }}
{{ render_field_with_errors(login_user_form.remember) }}
{{ render_field(login_user_form.next) }}
{{ render_field(login_user_form.submit) }}
</form>
{% endblock %}
In an abstract way I want to built something like a widget i can import and use in another template to implement such things only once, like the login form. Later i want to be able to implement lists, that can be placed in a siderbar on every page, without having it implemented on each page by itself. I found Flask Plugable Views but I haven't found a good example to understand the proper usage.
Update 2:
This (updated) implementation renders no form at all, without any error. I think I may have misunderstood the use of blocks.
** Solution **
With help from Mark I found the template context processor very helpful as kind of injection of variables. For some it might be obvious: flask-security provides the Forms as import, therefore my code now looks like this:
from flask.ext.security import LoginForm, RegisterForm
...
#app.context_processor
def inject_userForms():
return dict(login_user_form=LoginForm(), register_user_form=RegisterForm() )
I added the form directly into my layout.html which works well now. What does not work at all is the inclusion of the block. It works if I use blockception, using the login block within a content block.
Your error is:
UndefinedError: 'login_user_form' is undefined
This is coming from the template, which looks like this...
{% extends layout.html %}
{% block loginModal %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% include "security/_messages.html" %}
<h3>Login</h3>
<form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.email) }}
{{ render_field_with_errors(login_user_form.password) }}
{{ render_field_with_errors(login_user_form.remember) }}
{{ render_field(login_user_form.next) }}
{{ render_field(login_user_form.submit) }}
</form>
{% endblock %}
Therefore, you are referencing login_user_form, but Jinja2 is complaining that you haven't actually defined login_user_form. You typically define this when you are trying to call the function to render your template..
def my_view():
# ...
return render_template('login.html', login_user_form=login_user_form)
If you don't have the 'login_user_form' passed as an argument to render_template you will get the error.
If you are expecting login_user_form to be defined on the template context elsewhere in your application (such as in a template context processor), then ensure that that part of your application is indeed working.
Related
I have one template called skeleton.html
<head>
</head>
<body>
<div>
Some other code
</div>
<div>
{% block contact_info %}
{% endblock contact_info %}
</div>
</body>
And my other view is say home.html
{% extends "skeleton.html" %}
{% block contact_info %}
<div class="overflow-hidden">
<h4>Phone</h4>
<p class="lead">
{{ phone }}
</p>
</div>
{% endblock contact_info %}
So is this possible that I can use the block (contact_info) to any other template? Is there any way to reuse and render this block to another template file (e.g about.html)?
you can use include
for example
in your main template
{% include 'yourapp/yourtemplate.html' %}
I am making a child template in jinja which extends the parent template.In child template I am passing a variable to run a for loop in jinja template,but that part of for loop is not accessible inside the html page in chrome.
parent template-In parent template there is only navbar.
<html>
<head>
<link rel="stylesheet" href="static\navbar.css?v=1.1">
{% block head %}{% endblock %}
</head>
<body>
<nav class="menu">
<ul>
<li>Website</li>
<form action="{{ url_for('search') }}" class="search-form" target="_blank" method="POST">
<input type="text" name="text" placeholder="Search here..">
<button>Search</button>
</form>
{% if name %}
<li>{{name}}</li>
<li>Logout</li>
{% else %}
<li>Login & SignUp</li>
{% endif %}
<li><i class="fas fa-cart-plus"></i></li>
</ul>
</nav>
{% block content %}
{% endblock %}
</body>
</html>
Child template -In child template i am passing a variable for the for loop,but it is not working.
{% extends 'navbar.html' %}
{% block head %}
<title>Flipkart</title>
<!--new version 2nd way to update css-->
<link rel="stylesheet" href="static\gallary.css">
<script src="https://kit.fontawesome.com/04c28a3c9a.js"></script>
{% endblock %}
{% block content %}
<div class="description">
Shopping Website
</div>
<hr>
<h2>Deals Of The Day</h2>
<hr>
{% for i in ids %} -----this part is not coming in browser.----
<h1>sasadLink {{i}}</h1>
{% endfor %}
{% endblock %}
Flask file -- products function
#app.route('/products')
def products():
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute('SELECT id FROM shoes')
shoes_ids=cursor.fetchall()
print(shoes_ids)
ids = []
for shoes_id in shoes_ids:
ids.append(shoes_id['id'])
return render_template('navbar.html',ids=ids) ---here i am passing the
variable to the child
template-----
I want the for loop content to be displayed on the browser.
I'm trying to load a static css file but to no avail:
home.html:
{% extends 'base.html' %}
{% block body%}
{% load static %}
<link rel="stylesheet" href="{% static 'home/style.css' %}" type="text/css">
<div class="container">
<br/>
<form method="post">
{% csrf_token %}
{{ form.post }}
<br />
<button type="submit">Submit</button>
</form>
<h2>{{ text }}</h2>
{% for post in posts %}
<h1>{{ post.post }}</h1>
<p>Posted </b> on {{ post.created }}</p>
{% endfor %}
</div>
{% endblock %}
style.css:
.HomeForm {
size:20;
}
forms.py:
class HomeForm(forms.ModelForm):
post = forms.CharField(widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'How are you feeling?',
'size': '20',
}
))
I have a feeling I'm loading the static file in the wrong place, whats the solution? Thanks in advance.
You are loading the css file correctly. But that is not how you apply css classes to django forms.
Firstly, You are already giving bootstrap attributes to your field in your forms.py.
Now to apply the css classes change the following.
style.css
doesnt matter what you name your classes. No need to name them same as your Form name.
.home-post {
size:30; // Increase this to see difference
}
Now in your home.html add the class to your form. (Look for the comment). So now all the elements inside this container have size attribute too.
{% extends 'base.html' %} {% block body%} {% load static %}
<link rel="stylesheet" href="{% static 'home/style.css' %}" type="text/css">
<div class="container home-post"> <!--This is how you need to apply-->
<br/>
<form method="post">
{% csrf_token %} {{ form.post }}
<br />
<button type="submit">Submit</button>
</form>
<h2>{{ text }}</h2> {% for post in posts %}
<h1>{{ post.post }}</h1>
<p>Posted on {{ post.created }}</p>
{% endfor %}
</div>
{% endblock %}
EDIT:
Looks like you're using bootstrap but don't seem to load it. Add bootstrap if you didn't already add it in your base.html
I have setup my nav bar in my base.html as follows
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
{% if user.is_authenticated %}
<li>Logout</li>
<li>My Profile</li>
{% else %}
<li>Login</li>
<li>Register</li>
{% endif %}
</ul>
Now the problem is that I Don't want to execute the {% if %} block when user is not authenticated and when I am rendering a particular template page i.e
create_thing.html
{% extends 'layouts/base.html' %}
{% block title %} Create a Thing
- {{ block.super }}{% endblock %}
{% block content %}
<div id="content">
<h1> Create a Thing </h1>
<form role="form" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</div>
{% endblock %}
Simply copying the contents from Base and pasting it after removing doesn't help. It still executes base.html and gets inside the if statement and shows an error because slug wont be defined until I have filled details in create_thing.html.
Try nesting the {% if %} clause in another {% if not aux_var %} clause. Whenever you don't want to execute the first if, pass "aux_var":1 to the renderer as context.
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>
#}