Get checkbox option names when redndering manually - python

I'm trying to get the name of each option associated with a particular checkbox element. For example when I allow django to render the checkbox it produces
<label for="id_amenities_0"><input name="amenities" value="1" id="id_amenities_0" type="checkbox">
Care Parking</label>
Now I'm trying to render the forms manually and I want to find a way of displaying 'Care Parking'. This is what I have done but it doesn't display anything
{% for box in form.amenities %}
<div class="col-12 col-md-4">
<label class="custom-checkbox" for="id_amenities_{{ forloop.counter0 }}"> {{ box.html_name }}
<input type="checkbox" id="id_amenities_{{ forloop.counter0 }}" name="amenities">
<span class="checkmark"></span>
</label>
</div>
{% endfor %}

You're looking for choice_label:
{% for box in form.amenities %}
<label>{{ box.choice_label }}</label>
{% endfor %}

Related

HTML element to dynamically pop up specific suggestions for field in form

I'm working on a database tool using python+flask+werkzeug and learning how to use most of it for the first time. For the "Institution" field in the template, as the user starts typing in the name I would like existing options that fit the pattern to pop up in a drop-down, then with an option to add a new one if it's not found in that list. I've found the <select> element, and I can see a way to do it with that. However, it just has hard-coded in choices with no way to type in, and there may be hundreds of institutions I wouldn't want to put all in here. I don't know the terminology for the element I'm looking for so I don't really know what to google. Any thoughts?
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Add New Member{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="full_name">Full Name</label>
<input type="text" name="full_name" id="full_name" value="{{ request.form['full_name'] }}" required>
<label for="phone_number">Phone #</label>
<input type="tel" name="phone_number" id="phone_number" value="{{ request.form['phone_number'] }}">
<label for="email">Email</label>
<input type="email" name="email" id="email" value="{{ request.form['email'] }}">
<label for="institution_name">Institution</label>
<select id="institution_name" name="institution_name">
{% for institution in institution %}
<option value="{{ institution['institution_name'] }}">{{ institution['institution_name'] }}</option>
{% endfor %}}
<option value="not_found">Not found. Add new?</option>
</select>
<input type="submit" value="Submit">
</form>
{% endblock %}
There are JavaScript plugins that allow for this, such as Select2, but a simpler option could be to use a datalist element for this.
<div>
<datalist id="institution_list">
{% for institution in institution %}
<option value="{{ institution['institution_name'] }}">{{ institution['institution_name'] }}</option>
{% endfor %}}
</datalist>
<input autoComplete="on" list="institution_list"/>
</div>

How to modify css class using jinja2 macro

Hi guys i'm learning flask and have a problem. I'm trying to modify a input form control class based on validation.
In the jinja2 template i have the following (i'm using render_field) have imported the macro:
{% from 'includes/_formhelpers.html' import render_field %}
<div class="form-group">
<div class="input-group input-group-alternative mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-hat-3"></i></span>
</div>
{{ render_field(form.username, placeholder="Username",class="form-control") }}
</div>
</div>
And then in the macro file i have the following content:
{% macro render_field(field) %}
{{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
<input class="form-control is-invalid">
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% endif %}
{% endmacro %}
The problem is that the macro in rendering another input box
Generated HTML:
<div class="form-group">
<div class="input-group input-group-alternative mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-hat-3"></i></span>
</div>
<input class="form-control" id="username" name="username" placeholder="Username" required="" type="text" value="pandazulweb">
<input class="form-control is-invalid">
<div class="invalid-feedback">
Username already in use.
</div>
</div>
I think it's something related to kwargs and how i'm passing the class to the template but i'm a noob with jinja2
Unless I’m missing something, it looks like the second field is due to the ‘<input class=“form-control is-invalid”>’ which you’re including in the error condition of your macro.
EDIT: In order to pass the class to a form field, you need to use ‘class_=“is-invalid”‘, not ‘class=‘. So just use that and remove the second input from your error case.
EDIT 2: I think I see what the problem is. You need to put the first call to field() inside the macro’s error block, in the else block. So only if there is no error will it create the field with kwargs, etc.

Django/Bootstrap template rendering

I'm currently coding a website using Django and Bootstrap.
I created the templates and models first, and now, I'm implementing the controllers. All is not implemented yet, but I needed some help on this. I was wondering how to render a Django authentication form with the Boostrap grid system. I'm using Boostrap 4 and Django 2.0.4. My older form was like this :
<div class="jumbotron">
<form class="form-horizontal" method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group">
<div class="col-lg-4 offset-lg-4">
<label class="control-label" for="usernameInput">{{ form.username.label_tag }}</label>
<input id="usernameInput" type="text" name="{{ form.field.html_name }}" value="{{ form.username }}" class="form-control"
placeholder="Username">
</div>
</div>
<div class="form-group">
<div class="col-lg-4 offset-lg-4">
<label class="control-label" for="passwordInput">{{ form.password.label_tag }}</label>
<input id="passwordInput" type="password" name="{{ form.field.html_name }}" value="{{ form.field.value }}" class="form-control"
placeholder="Password">
</div>
</div>
<div class="container" id="btn_login">
<button type="submit" class="btn btn-primary btn-md" value="login" role="button">Log in</button>
<input type="hidden" name="next" value="{{ next }}"/>
</div>
</form>
<span class="container" id="forgotten_password">
Forgot your password ?
</span>
</div>
And here is the new one :
<div class="jumbotron">
{% load widget_tweaks %}
<form class="form-horizontal" method="post" action="{% url 'login' %}">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<div class="container" id="btn_login">
<button type="submit" class="btn btn-primary btn-md" role="button">Log in</button>
</div>
</form>
<span class="container" id="forgotten_password">
Forgot your password ?
</span>
</div>
But as you can obviously tell, this is not rendering the same way.
For example, I'd like to take back the width of the input.
For the rest, I use this line in my urls.py
re_path(r'^login/$', auth_views.login, {'template_name': 'main/login.html'}, name='login'),
And this one in my settings.py to get redirected to the right page :LOGIN_REDIRECT_URL = 'my_pls'
I googled a lot and finally used this link (in case you case notice something I didn't understand) : https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html#understanding-the-rendering-process
You should use custom HTML attributes on your **forms.py**.
It's simple:
from django import forms
class your_form(forms.Form):
attrs_for_the_field = {
'class': 'form-control',
'placeholder': 'Write here!',
}
field = forms.CharField(widget=forms.CharField(attrs=attrs_for_the_field))
With this code you will render the following HTML:
<input type="text" name="field" class="form-control" placeholder="Write here!" id="id_field">
Take a look at https://docs.djangoproject.com/en/2.0/ref/forms/widgets/ in order to know how Django represents an HTML input element.
You also should read https://docs.djangoproject.com/en/2.0/ref/forms/fields/ so that you could understand how it works.
You can add all the HTML configuration for the fields in the form code in forms.py . Than the form can be displayed with just {{ form.as_p}}.
Width of input can be retrieved with jQuery or JavaScript .

How do I reference an object property in a method call in Jinja2?

I am trying to render a form in a flask app using jinja2 and flask-wtf, but am having trouble figuring out how to handle adding a generated argument for onclick that contains a property as part of it's argument.
You can see in the form label section I have onclick set to call a javascript function and pass the name property of the current loop object and this works as intended. However when I am in the form field section, I need to pass onclick to the loop object as a key word argument, and need to make the argument of my argument the object name property. This doesn't work.
Here is a shortened example:
<form class="form">
{% for entry_field in form %}
{{ entry_field.label() }}
{{ entry_field(onclick="jsFunction({{entry_field.name}})}}
{% endfor %}
</form>
Here is a full example:
<form id="reg_form" class="form text-left" method="post" role="form">
{{ form.csrf_token }}
{% for entry_field in form %}
{% if entry_field != form.csrf_token %}
<div class="form-group row">
<!--form label-->
<a href="#" onclick="showNotes('{{entry_field.name}}')">
{{ entry_field.label(class="col-sm-3 col-form-label") }}
</a>
<!--form field-->
<div class="col-sm-9">
{{ entry_field(class_="form-control", onclick="showNotes('{{entry_field.name}}')") }}
{% for error in entry_field.errors %}<span style="color: red;">{{ error }}</span>{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
<!--form submit-->
<div class="form-group row">
<div class="col-sm-9 col-sm-offset-3">
<input type="submit" class="btn btn-lg btn-success" value="Submit">
</div>
</div>
</form>
Greatly appreciate any help!
You can use string formatting to build a string you want:
{{ "jsFunction(%s)" | format(entry_field.name) }}
And that string you can use as the parameter for entry_field():
{{ entry_field(onclick=("jsFunction(%s)" | format(entry_field.name)) }}

Is it possible to instantiate a formset which isn't call with {{ formset.as_p }}?

I call a formset but not with {{ formset.as_p }} because I want to change the display of forms.
I know when using {{ formset.as_p }} it is possible to instantiate a field to edit it directly.
But is that possible using a formset that way
<form method="POST" action="">
{{ formset.management_form }} {% csrf_token %}
<table>
<!-- <br>{{ formset.as_p }}<br> -->
{% for question in questions %}<hr>
<label for="question">{{ question }} [{{ question.id }}]</label>
<input type="hidden" id="id_form-{{ forloop.counter0 }}-question" name="form-{{ forloop.counter0 }}-question" value="{{ question.id }}"/>
</p>
<p>
<label for="answer">Answer :</label>
<input type="text" id="id_form-{{ forloop.counter0 }}-answer" name="form-{{ forloop.counter0 }}-answer" placeholder="answer here"/>
<input type="hidden" id="id_form-{{ forloop.counter0 }}-id" name="form-{{ forloop.counter0 }}-id" value="{{ reply.id }}"/>
</p>
{% endfor %}
</table>
<center><input type="submit" value="Submit" class="btn btn-success" />
Retour</center>
</form>
I wish I could instantiate the fields answer.
I tried passing in a values like this :
{% for reply in question.reply_set.all %}
<p>
<label for="answer">Réponse :</label>
<input type="text" id="id_form-{{ forloop.parentloop.counter0 }}-answer" name="form-{{ forloop.parentloop.counter0 }}-answer" value="{{ reply.answer }}"/>
<input type="hidden" id="id_form-{{ forloop.parentloop.counter0 }}-id" name="form-{{ forloop.parentloop.counter0 }}-id" value="{{ reply.id }}"/>
</p>
{% endfor %}
But by doing it like this just initializes the values and does not allow to modify
There has a way to do what I wish with this formset structure?
EDIT :
class ReplyForm(forms.ModelForm):
def __init__(self, page_id, *args,**kwargs):
super (ReplyForm,self ).__init__(*args,**kwargs)
self.fields['question'].queryset = Question.objects.filter(page=page_id)
class Meta:
model = Reply
exclude = ('user','creationDate')
If I got you right, you want to customize the view of a form rendered with a formset. Of course, you can do it, since formset is just a set of forms. Render a formset manually and do so with the form as well.
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
# more fields
{% endfor %}
</table>
</form>
In case you have multiple items field (question in your case) in one form you can itterate them and render manually as well:
{% for field in form.question %}
<div class="fieldWrapper">
{{ field.errors }}
<label for="{{ field.id_for_label }}">Some label:</label> {{ field }}
</div>
{% endfor %}

Categories

Resources