Django: Extent with snippets or better solution - python

I have the following template:
{% extends "account/base.html" %}
{% load i18n %}
{% load account %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "Password Reset" %}{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
<h1>Reset your password</h1>
{% if user.is_authenticated %}
{% include "account/snippets/already_logged_in.html" %}
{% endif %}
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p>
<form method="POST" action="{% url 'account_reset_password' %}" class="password_reset">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Reset My Password</button>
</form>
<p><em>{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}</em></p>
</div>
</div>
</div>
{% endblock %}
account/base.html contains this here:
{% extends "base.html" %}
base.html then contains tags etc. I am currently struggling with finding the best solution while considering DRY. In my template I have written:
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
[more text]
</div>
</div>
</div>
I have several of these templates and in each of them I am currently writing the same ... I am now wondering is the right solution to include these opening / closing div-tags in two files and then add
{% include "div-open.html" %}
[more text]
{% include "div-closing.html" %}
Or is there any better solution to this? It doesn't feel right, that's why I am asking you now how you would solve this.

I depends if HTML repetition should be considered as DRY violation. I you have custom form fields which you want to include, than having {% include 'simple_custom_field.html' with field=form.some_fied %} where
simple_custom_field.html
<input
type="{{ field.field.widget.input_type }}"
class="form-control {{ field.field.widget.attrs.class }} {{ class }}"
id="{{ field.id_for_label }}"
name="{{ field.html_name }}"
placeholder="{{ field.label }}"
{% if field.value is not None %} value="{{ field.value }}"{% endif %}>
or like that...
is good idea, or you can render whole form like that also if you have long blocks or separate blocks of HTML in multiple files, then go for it. But its bad idea for including simple and fundamental parts of HTML. It should be transparent for the programmer.
If you want to do it another way, there are ways how to add custom template tags and "modify" the language you write templates in.
Here is docs how to do it: Writing custom template tags | Django docs

Related

flask render_template passed variable not being used in the template

I'm currently working on a project and I'm having a problem with flask and render_template. When I pass a variable into render_template, it doesn't actually pass through to the template. I've already tried putting the string into a variable and a few other things but nothing has worked so far.
Here's the function I'm returning:
return render_template("sell.html", error="Invalid Ticker")
Here's "sell.html":
{% extends "layout.html" %}
{% block title %}Sell{% endblock %}
{% block main %}
<h1>Sell a Stock!</h1>
{% if error is defined %}
<div class="alert alert-danger">
{{error}}
</div>
{% endif %}
{% if success is defined %}
<div class="alert alert-success">
{{success}}
</div>
{% endif %}
<form action="/sell" method="post">
<div class="form-group">
<label for="ticker">Ticker:</label>
<input type="text" class="form-control" id="ticker" name="ticker">
</div>
<div class="form-group">
<label for="buynum">Shares:</label>
<input type="number" class="form-control" id="sellnum" name="sellnum">
</div>
<button type="submit" class="btn btn-primary">Sell</button>
</form>
{% endblock %}
The problem is not in the render_template function it is working fine. The problem is error is defined doesn't exists in jinja2.
just try a simpler html example to test:
{% block title %}Sell{% endblock %}
{% block main %}
<p> {{error}} </p>
{% endblock %}
so change :
{% if error is defined %}
and
{% if success is defined %}
to
{% if error %}
{% if sucess %}

Flask square brackets and single quotas at showing all validation message at once

I have created a very simple login form with flask
email = StringField('E-Mail:', validators=[validators.DataRequired(message='E-mail needed.'), validators.email(u'Provide e-mail.')])
password = StringField('Password:', [validators.required(u'Password can't be empty.')])
And the macro which will create the form inside the template:
{% macro render_field(field) %}
<fieldset>
<div class="form-group">
{{ field(**kwargs) | safe }}
</div>
</fieldset>
{% endmacro %}
As you can see it is very simple form. In the flask tutorial it was showing validation erors for individual fields. But I just want to show them all at once on the top of the form.
Here is my template for that:
<div class="panel-body">
{% if loginForm.errors %}
<div class="alert alert-danger">
<ul>
{% for error in loginForm.errors %}
<li>{{ loginForm.errors[error] }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<form role="form" method="post" action="{{ url_for('login') }}">
{% from "_formhelper.html" import render_field %}
<fieldset>
{{ render_field(loginForm.email, class="form-control", placeholder="E-Mail") }}
{{ render_field(loginForm.password, class="form-control", placeholder="Password") }}
<button class="btn btn-lg btn-success btn-block">Login</button>
</fieldset>
</form>
</div>
As you can see, i placed my error section on the top of the form. But when
I post empty form, it shows the error messages like this:
['Password can't be empty'] instead of Password can't be empty
Why does it append square brackets and single quotas, start and end of the message? I don't know.
I know that this is an old question but if anyone else has this problem you can fix it by adding a for loop for the messages, something like this:
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning my-5">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}

flask-admin: revise the button text

I haven't found similar questions on stackoverflow, I'd like to change the save button to submit or confirm on the edit form. I know this might not be easily changed. Thanks for any advise in advance.
After search in the code of flask-admin, I found the button is rendered with macro render_form, render_form_buttons, extra. The value of these buttons is hard code with {{ _gettext("blabla") }}.
As these buttons are not fields of data model, we can't use rendering rules to custom the value. I think there are two work arounds to get this done:
change the macro which render these buttons in the source of flask-admin(render_form_buttons, extra)
flask-admin use flask-babelex to do localization({{ _gettext("blabla") }}), you can 'translate' Save to submit or confirm with flask-babelex
UPDATE:
You can custom edit.html in your own template directory.
{% extends 'admin/model/edit.html' %}
{% from 'admin/lib.html' import extra with context %}
{% from 'admin/lib.html' import form_tag with context %}
{% from 'admin/lib.html' import render_form_fields with context %}
{% macro my_render_form_buttons(cancel_url, extra=None, is_modal=False) %}
<hr>
<div class="form-group">
<div class="col-md-offset-2 col-md-10 submit-row">
<input type="submit" class="btn btn-primary" value="{{ _gettext('Submit') }}" />
{% if extra %}
{{ extra }}
{% endif %}
{% if cancel_url %}
<a href="{{ cancel_url }}" class="btn btn-danger" role="button" {% if is_modal %}data-dismiss="modal"{% endif %}>{{ _gettext('Cancel') }}</a>
{% endif %}
</div>
</div>
{% endmacro %}
{% macro my_render_from(form, cancel_url, extra=None, form_opts=None, action=None, is_modal=False) -%}
{% call form_tag(action=action) %}
{{ render_form_fields(form, form_opts=form_opts) }}
{{ my_render_form_buttons(cancel_url, extra, is_modal) }}
{% endcall %}
{% endmacro %}
{% block edit_form %}
{{ my_render_form(form, return_url, extra(), form_opts) }}
{% endblock %}

Using stylesheets with django-widget-tweaks?

I'm struggling to understand how to use Django-Widget-Tweaks with a stylesheet. For example, here's my basic form with bunch of CSS classes pulled from my stylesheet - obviously not yet wired up with Django.
<form name="form">
<div class="md-form-group float-label">
<input type="email" class="md-input">
<label>Email</label>
</div>
</form>
How should this be used with Django-Widget-Tweaks? I'm presuming it's something like this but I'm struggling to understand where the div classes go...
<div>
{% load widget_tweaks %}
{{ form.myform|add_class:"md-form-group float-label md-input" }}
</div>
Thanks!
This is how I do it by using render_field tag. Hope this helps.
{% load widget_tweaks %}
<form name="form">
{% for field in form %}
<div class="md-form-group float-label">
{% render_field field class="md-input" %}
<label>{{ field.label_tag }}</label>
</div>
{% endfor %}
</form>

Reference list items by index Django template

I have a list called forms which I am passing to a Django (1.5.1) template:
<div class="content">
{% if forms %}
<form method="POST" enctype="multipart/form-data" class="survey">
<div class="image">
{{ forms.0.as_p }}
</div>
<div class="questions">
{% for form in forms %}
{{ form.as_p }}
</div>
{% endfor %}
<input type="submit" value="Submit Survey"/>
</form>
{% endif %}
<div class="content">
I want to do two separate things:
Put the first element of the forms list inside a div tag with class="image".
Put the rest of the elements inside a div tag with class="questions"
There are SO questions about how to reference list items by index inside a django template, but forms.0.as_p doesn't render anything for me. Also, how to get a sublist of items from forms (something like forms[1:])?
EDIT
While the question has been correctly answered below, I'll add another way of doing it using slice.
<form method="POST" enctype="multipart/form-data" class="survey">
<div class="image">
{{ forms.0.as_p }}
</div>
<div class="questions">
{% with myforms=forms|slice:"1:"%}
{% for form in myforms %}
{{ form.as_p }}
{% endfor %}
{% endwith %}
</div>
Use the forloop.first variable to determine the first form in the list:
{% for form in forms %}
<div class="{{ forloop.first|yesno:'image,question' }}">
{{ form.as_p }}
</div>
{% endfor %}
P.S. You don't need it for this case but to get the sublist in the template you can use the slice template filter.

Categories