Flask-security and Bootstrap - python

How can I style my Flask-security login site with Bootstrap? The html form looks like this:
<form action="{{ url_for_security('login') }}" method="POST" name="login_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>
Bootstrap is implemented, but I dont know how to edit the fields and the submit button..

The render_field_* functions accepts a class_ parameter, which will add HTML classes to the field. Add in bootstrap styling classes as you want.
render_field_with_errors(login_user_form.email, class_="form-control") }}
{{ render_field(login_user_form.submit, class_="btn btn-default") }}
And so on.

Flask-Security uses Flask-WTForms to render and validate forms. In Flask-Security 1.7.5, the default render_field_with_errors and render_field macros defined in "security/_macros.html" are
{% macro render_field_with_errors(field) %}
<p>
{{ field.label }} {{ field(**kwargs)|safe }}
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</p>
{% endmacro %}
{% macro render_field(field) %}
<p>{{ field(**kwargs)|safe }}</p>
{% endmacro %}
According to the Flask-WTForms 0.10 docs, both of the above macro functions accept ...
... keyword arguments that are forwarded to WTForm’s field function that renders the field for us. The keyword arguments will be inserted as HTML attributes.
Specifically, the lines {{ field(**kwargs)|safe }} pass the HTML escaped keyword arguments to the field function. Therefore, you can add classes,
{{ render_field_with_errors(login_user_form.email, class="form-control") }}
and can also overwrite default HTML attributes,
{{ render_field_with_errors(login_user_form.email,
class="form-control", type="email", placeholder="Enter email") }}
{{ render_field(login_user_form.submit, class="btn btn-default", value="Submit" ) }}
Additionally, you can define your own macros by modifying the macros above. For example, if you wanted to use Bootstrap alerts to render form validation errors, you could define the macro function render_field_with_bootstrap_errors
{% macro render_field_with_bootstrap_errors(field) %}
<p>
{{ field.label }} {{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
{% endif %}
</p>
{% endmacro %}
Adding your own macro is pretty simple. For example, you can put custom macros in a "custom_macros.html" file within the templates directory and then load the functions into templates with
{% from "custom_macros.html" import render_field_with_bootstrap_errors %}
This way, it is easy to modify the macros to use different Bootstrap features.

Related

Safe built-in inside for loop Django CKEditor

I'm using CKEditor with Django and when i need show some RTF code in my template, usually, I use the safe built in filter (autoscape).
Example:
<p class="card-text">{{ questao.enunciado|safe }}</p>
But, how to use safe built-in inside a for loop?
{% for field in form %}
<div class="fieldWrapper">
<strong>{{ field.label_tag }}</strong>
{{ field|safe }}
{% if field.help_text %}
<p class="help">{{ field.help_text }}</p>
{% endif %}
</div>
{% endfor %}
This way above is not working for me, and in the template it ends up showing me HTML codes in text format.
You need not use the safe for the field.
Try:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
Also refer django documentation
You are applying safe filter to the wrong value. You have to apply it to field.label or field.help_text instead, e.g.:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
<label for="{{ field.id_for_label }}">{{ field.label|safe }}</label>
{{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}

Flask Jinja 2 Rendering Issue

I am sure I am doing something wrong .
{% block content %}
<h1>Sign In</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}
</p>
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
{% extends "base.html" %}
Above code gives this output:
Which is correct. But when i change same code to as below :
{% extends "base.html" %}
{% block content %}
<h1>Sign In</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}
</p>
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
Output becomes like this:
My base.html looks like this:
<div>
Home
Login
</div>
I am sure , i am making some silly mistake but can not seem to find it .
if i copy the code from base.html on top of my code it renders correctly.
Hope someone can help.
You need to have a content block to override in your base.html
<div>
Home
Login
{% block content %}{%endblock%}
</div>
Your base.html should contain blocks in it for the various content blocks that you will have in your site.
When you create a new page and want to override that content or add content to those blocks you use extends like you have done.
{% extends "base.html" %}
{% block content %}
Your content goes here
{% endblock %}
You can have multiple blocks in your base.html and then override them when you want.
Jinja documentation
You can put content in the content blocks in your base html and then add to that content without overriding it using the super() function.
{% block content %}
{{ super() }}
New content here
{% endblock %}
The above can be handy for script files. If you have some that need to be site wide, and some only on specific pages.

Invalid filter: 'markdown' django-markdown-deux

Before I explain my issue, let me tell you some basics of my system:
windows 10
python 3.6
django 1.9
I followed the documention of 'django-markdown-deux', from it, I learned it has four steps to be implemented.
Firstly: pip3 install django-markdown-deux
Secondly: add markdown_deux into your INSTALLED_APPS
Thirdly: add {% load markdown_deux_tags %} into your header.html
Finally: add {{ post.body|markdown }}, as I want to transfer post.body to markdown
{% extends "personal/header.html" %}
{% block content %}
<h3>{{ post.title }}</h3>
<h6> on {{ post.date }}</h6>
<div class = "container">
{{ post.body|markdown }}
</div>
<br><br>
{% endblock %}
after doing this, I have "Error during template rendering"
In template F:\django\mysite_1\blog\templates\blog\post.html, error at line 8
Invalid filter: 'markdown'
You need to load the tags in the template file which uses the tags (not in your header.html). In other words, you need to include {% load markdown_deux_tags %} in the same file as you call {{ post.body|markdown }}:
{% extends "personal/header.html" %}
{% load markdown_deux_tags %}
{% block content %}
<h3>{{ post.title }}</h3>
<h6> on {{ post.date }}</h6>
<div class = "container">
{{ post.body|markdown }}
</div>
<br><br>
{% endblock %}

Render field errors in for loop with Flask-WTF

I would like to iterate over form's fields in a template and display fields with errors like this:
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{% if form.errors.field %}
<div class="has-error"> {{ field.label }} {{ field(size=80, class_='form-control') }}</div>
<span style="color: red;">{{ form.errors.field.0 }}</span>
{% else %}
{{ field.label }} {{ field(size=80, class_='form-control') }}
{% endif %}
{% endfor %}
But that doesn't work for some reason- the form renders but the errors are not displayed.
I've already checked solutions here, and here, and also here and none of those have helped.
Could someone please advise how to fix my form to correctly render the errors?
The issue is in using form.errors.field. This would only be accurate in jinja if you had a field named field and not for any other names.
Fortunately, you're already iterating fields, and every field has a .errors property so the shortest solution is to simply use that property
Your code should look something like:
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{% if field.errors %}
<div class="has-error"> {{ field.label }} {{ field(size=80, class_='form-control') }}</div>
<span style="color: red;">{% for error in field.errors %}{{ error }}{% if not loop.last %}<br />{% endif %}{% endfor %}</span>
{% else %}
{{ field.label }} {{ field(size=80, class_='form-control') }}
{% endif %}
{% endfor %}

Is there a way to hide the csrf label while looping through form using Flask and Flask-WTForms?

I have very simple contact form and I would like to hide the label somehow so that it doesn't show Csrf Token. I am using Flask and Flask-WTForms and am rendering the form like this:
{% for field in form %}
{{ field.label }}
{{ field }}
{% endfor %}
So basically this shows my inputs correctly and the csrf oen is hidden but the label isn't hidden? Should I get over it and implicitly say form.field_name instead of looping through the form or is there a way to handle this "corner case".
I was thinking about doing a logical check in either the for loop declaration or the label declaration but so far I haven't found anything in the documentation that has worked.
Thanks
EDIT: I have "fixed" the problem by doing this but it feels kinda dirty and hacky which I don't like I am still open to a better solution:
{% if not loop.first %}
{{ field.label }}
{% endif %}
If you want a more general solution that works for all hidden fields instead of just the CSRF token:
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{{ field.label }}
{{ field }}
{% endfor %}
form.hidden_tag() is supplied by Flask-WTF.
Just to add to JD's excellent answer...
For those stumbling across this question: You can avoid losing the (csrf) hidden field (and thus protection) by adding the condition "if field.widget.input_type!='hidden' " specifically to the label instead of to the form iterator.
i.e.:
not
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{{ field.label }}
{{ field }}
{% endfor %}
but
{{ form.hidden_tag() }}
{% for field in form %}
{% if field.widget.input_type != 'hidden' %} {{ field.label }} {% endif %}
{{ field }}
{% endfor %}
I think this should work too:
{% for field in form if field.id != 'csrf_token' %}
{{ field.label }}
{{ field }}
{% endfor %}
I have found the way to do it like this:
{% if field.id != 'csrf_token' %}
I believe this to be less hacky. I found this from modifying the example here in the docs.
I made a macro recently to submit forms through ajax in order to not reload the webpage and send it to the api directly.
{% macro render_fields3(form, form_name, method) %}
<form class="ajax" name={{ form_name }} method={{ method }}>
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
<dt>{{ field.label }}
<dd>{{field(id=field.name + method)|safe}}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endfor %}
</form>
{% endmacro %}

Categories

Resources