Jinja2 to put a whole element in <option> - python

I need to dynamically select from the following:
So that I can show the selected element depending on POST request.
I want to templatize selected="selected" so that I can choose where to put.
<select name="my_name">
<option value="5min">5-Min</option>
<option value="1hour" selected="selected">Hour</option>
<option value="1day">Day</option>
</select>

Assume target is the desired value that you want to select (obtained from the POST dictionary).
Then you need two things:
Prepare a dictionary containing value - display text pairs for all options in the select, e.g
mydict = {'5min': '5-Min', '1hour': 'Hour', '1day': 'Day'}
In yourtemplate.html:
<select name="my_name">
{% for key, value in mydict.items() %}
<option value="{{key}}"
{% if (key == target) %} selected="selected" { %endif %}
>
{{value}}
</option>
{% endfor %}
</select>
How to pass the target - in your view you need to do this (I assume you know the basics of views in Flask)
target = request.form['key_of_the_data_we_need'] # the value that should be selected
mydict = {'5min': '5-Min', '1hour': 'Hour', '1day': 'Day'} # helper for the select
return render_template('yourtemplate.html', target=target, mydict=mydict)
This way, the data is sent to yourtemplate.html which contains the code discussed above, therefore selecting the desired <select> option.

Using the same approach as Pawel did, I just changed some small things in order to work with my actual version of Jinja2:
<select class="form-control" id="worker" name="worker">
{% for key in workers %}
<option value="{{key}}" {% if key == people.worker %} selected="selected" {% endif %}>
{{key}}
</option>
{% endfor %}
</select>
And from the controller:
workers = {'First One','Second One', 'Third One'}
return render_template('edit.html', people=people, workers=workers)
Remember to put the controller code within the controller which is passing the data for the view.

It is not totally clear to me what the background of your question is. If the reason is that you can't use wtf.quick_form(yourform) because you need some customization, you could simply use
{{ form.workers.__call__(**{'class': 'form-control'}) }}
for the respective field in your Jinja2 template. This selects the posted element in the form. Note how I define additional attributes (a class).
The result will be (for example):
<select class="form-control" id="worker" name="worker">
<option value="0">text1</option>
<option selected value="1">text2</option>
<option value="2">text3</option>
</select>
This of course requires that you have a properly defined form:
class yourform(FlaskForm):
workers = SelectField(
'name',
validators=[Required()],
choices=[(0, 'text1'), (1, 'text2'), (2, 'text3')],
coerce=int
)
(... whatever other fields here ...)

Related

can i do process with form django python

there is a input and select with options in form tag. i want to get input value and option that entered. and i will do somethings on backend with python that value and option than i will return a result to website. but i dont use to forms.py. how can i do? is it possible?
<form action="" method="post">
{% csrf_token %}
<input type="text" name="getinputValue">
<select name="">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
</select>
<button type=""class=""></button>
<p>{{result}}</p>
</form>
So, from what I understanding in your question, you want to retrieve the data from the form in your views and do something with it. You will have to give your <select> a name attribute so that you can reference it in your views.
<select name="level">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
</select>
In your views, one of the ways you can retrieve this data is by:
def options_view(request):
level = request.POST.get('level') # get name of option as specified in the <select> tag
# here you can do something with it
print(level)
return render(request, 'home.html', {'level': level})
This is one way to do it.

disabling one of the options in WTForms SelectField

What is the simplest way to assign 'disabled' html attribute to one of the options in SelectField in WTForms?
This is my previous code
<select class="form-control" name="division" data-error="Required!" required>
<option value="default" disabled selected>Select something</option>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
As you can see I would like to set 'disabled' only to first option.
My code for this task is:
next(form.division.__iter__())(**{'disabled':'true'})
And using print function in console I can see the proper output:
<option disabled="true" selected value="default">Select something</option>
The line is working, but somehow this output is not passed to the template.
Instead this is what's passed:
<option selected value="default">Select something</option>
Please someone make it clear.
If you simply just want a disabled and selected option as the first option of your select, I found this to be simpler than extending the SelectField class:
Just loop over the option and check for first loop iteration
<select name="my_select" id="my_select">
{% for option in form.my_select %}
{% if loop.first %}
<option value="" disabled selected>select something</option>
{% endif %}
{{ option }}
{% endfor %}
</select>
Here's a custom wtforms widget which makes use of the SelectField's Options iterator.
from markupsafe import Markup
from wtforms.widgets.core import html_params
class CustomSelect:
"""
Renders a select field allowing custom attributes for options.
Expects the field to be an iterable object of Option fields.
The render function accepts a dictionary of option ids ("{field_id}-{option_index}")
which contain a dictionary of attributes to be passed to the option.
Example:
form.customselect(option_attr={"customselect-0": {"disabled": ""} })
"""
def __init__(self, multiple=False):
self.multiple = multiple
def __call__(self, field, option_attr=None, **kwargs):
if option_attr is None:
option_attr = {}
kwargs.setdefault("id", field.id)
if self.multiple:
kwargs["multiple"] = True
if "required" not in kwargs and "required" in getattr(field, "flags", []):
kwargs["required"] = True
html = ["<select %s>" % html_params(name=field.name, **kwargs)]
for option in field:
attr = option_attr.get(option.id, {})
html.append(option(**attr))
html.append("</select>")
return Markup("".join(html))
When declaring the field, pass an instance of CustomSelect as the widget parameter.
division = SelectField(
"Division",
choices=[("default", "Select something"), ("option1", "Option 1"), ("option2", "Option 2")],
validators=[InputRequired()],
widget=CustomSelect(),
default="default",
)
And to pass attributes when rendering
form.division(option_attr={"division-0": {"disabled": ""} }, class="form-control")
When you disable the field the values are no longer passed. What you might want to do is pass the variable by using read only instead of disabled. Here's how do to it with jquery :
$('#id_of_option').prop('readonly', true);
Also what I've done is set choices in Wtforms where
choices = [('', 'please select an option'), ('1', 'option 1'), ('2', 'option 2')]
and this way a user has to select a value.
This worked for me.
<select id="{{ form.my_select.id }}" name = "{{ form.my_select.name }}">
{% for option in form.my_select %}
{% if loop.first %}
{{ option(disabled="") }}
{% else %}
{{ option }}
{% endif %}
{% endfor %}
</select>
The HTML 'disabled' attribute is a boolean one and in regular HTML, it does not need to be assigned to "". Without the equal sign, I got some positional argument errors.
If you want to disable other options (say, 4th and 5th option in addition to the first one), you can do this:
<select id="{{ form.my_select.id }}" name = "{{ form.my_select.name }}">
{% for option in form.my_select %}
{% if loop.first %}
{{ option(disabled="") }}
{% elif loop.index == 4 or loop.index == 5 %}
{{ option(disabled="") }}
{% else %}
{{ option }}
{% endif %}
{% endfor %}
</select>
Note that loop.index is 1-based.

Django custom form template

I've a custom template to render my form in my Django website. This code renders the ChoiceFields:
<select id="{{ "id_"|add:field.html_name }}"
class="form-control"
name="{{ field.html_name }}">
{% for id, name in field.field.choices %}
<option value="{{ id }}"
{% if field.value|default_if_none:"" == id %}
selected="selected"
{% endif %}
>{{ name }}</option>
{% endfor %}
</select>
This code works perfectly, when the ChoiceField does not have an initial value. If I sumbit the form, but there's an error in the form (sp I get back to my form, and all the data is in there as I submitted it), the correct choice get the selected="selected" attribute, so it works perfectly fine.
But when I set the default value for the form in my Django view (correctly in the form's init() function, like this: self.fields['card_type'].initial = self.card.card_type_id), this stops working.
If I put manually somewhere in my template the form.value variable it displays the correct integer. In the id, name for-loop there's the same id value. These do not have any whitespace ot something else there. But the code does not works, does not equals to true the self.fields['card_type'].initial = self.card.card_type_id condition.
If I modify the previous code, to print the id, and the field.value instead of the {{name}}, like this: ({{id}}-{{ field.value }}), the following HTML code'll be generated:
<select id="id_card_type" class="form-control" name="card_type">
<option value="3">(3-2)</option>
<option value="2">(2-2)</option>
<option value="1">(1-2)</option>
</select>
There's the id, which is 1, 2, and 3! There's the form.value, which is 2! But there isn't any selected="selected"... Why not working?
Thanks!

as a template to make a series of dictionary?

I pass to the template dictionary
CHOICES_gender = (('0', 'М'), ('1', 'Ж'))
I need to put in the element 'select' keys and values ​​CHOICES_gender.
I try to do as follows:
<select class="fld_gender" id="fld_gender">
{% for (key, item, ) in CHOICES_gender.values() %}
<option name="key" value="volvo">item</option>
{% endfor %}
</select>
but get the following error:
Exception Type: TemplateSyntaxError
Exception Value:
Could not parse the remainder: '()' from 'CHOICES_gender.values()'
I think this will fix your problem :)
<select class="fld_gender" id="fld_gender">
{% for key, item in CHOICES_gender %}
<option name="{{ key }}" value="volvo">{{ item }}</option>
{% endfor %}
</select>
There is no need to call the function .values() on the tuple.
The CHOICES_gender you provided is not a dict object
perhaps you omitted a step when converting it to be a dictionary?
CHOICES_gender = {'0':'М', '1':'Ж'}
and then the correct syntax is:
<select class="fld_gender" id="fld_gender">
{% for key, item in CHOICES_gender.items %}
<option name="key" value="volvo">item</option>
{% endfor %}
</select>
You could convert your existing object to a dictionary:
CHOICES_dictionary = { o[0]:o[1] for o in CHOICES_gender }
If you want to keep the object as is:
CHOICES_gender = (('0', 'М'), ('1', 'Ж'))
You can unpack it similar to you would in a python:
<select class="fld_gender" id="fld_gender">
{% for key, item in CHOICES_gender %}
<option name="key" value="volvo">item</option>
{% endfor %}
</select>
Your error was being thrown because you cannot call methods on objects in a django template with parentheses at the end which is why it complained about the () on the end.
ref: Django Book Ch 4, About a 1/3 of the way down the page in "Context Variable Lookup"
As a side note, you will never be able to call a method with arguments, in which case you can write a filters if you really feel the need, but generally all the data needs to be some what serialized, i.e. staticly laid out instead of generated in the template.
Typically you do any preparation of the data in the views.py and then give presentation logic in the template.

Django Select Post Request(return id, not value)

I have code:
<select class="form-control" id="engine" name="engine">
{% for engine in engines %}
<option name="{{engine.id}}">{{engine.name}}</option>
{% endfor %}
</select>
print request.POST:
<QueryDict: {u'engine': [u'test1'], u'csrfmiddlewaretoken': [u'9rICLe2X1m0KBnxLjY7V2gYoeV5Dd3m6']}>
I want get id in "engine"(not value). How I can do it?
Change this line <option name="{{engine.id}}">{{engine.name}}</option> to:
<option value="{{engine.id}}">{{engine.name}}</option>
What do you mean by
I want get id in "engine"(not value)
You mean in your view? Isn't that simply
request.POST['engine']

Categories

Resources