as a template to make a series of dictionary? - python

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.

Related

Django - Passing multichoice field into POST dictionary

I have a queryset generated in my forms.py file that passes into my template. The template result is a multichoice field based on the queryset. The web browser presentation is correct - it renders the queryset as a drop down choice list that I can make a selection from.
Here is the template code:
<tr><td>{{ form.jury_name | placeholder:'Jury Name' }}</td></tr>
<tr><td><select>
{% for item in form.parent_jury.field.queryset %}
<option name="parent_jury" value="{{ item }}">{{ item }}</option>
{% endfor %}
</select></td></tr>
This is all contained in a table.
When the form is submitted (method = "POST") the POST dictionary has all the correct values for the keys except the parent_jury key which posts a value of ''.
I've worked through several SO solutions on the views.py side, but they don't change the fact that the information available for a clean() is missing the choice field value for 'parent_jury'. How do I get the selected option from the list to attach to the 'parent_jury' key?
I think your rendered HTML is not the way it is supposed to be: the name="..." should be part of the <select> tag, not the <option>s:
<tr><td>{{ form.jury_name | placeholder:'Jury Name' }}</td></tr>
<tr><td><select name="parent_jury">
{% for item in form.parent_jury.field.queryset %}
<!-- remove the name here -->
<option value="{{ item }}">{{ item }}</option>
{% endfor %}
</select></td></tr>
(of course you can remove the <!-- comment --> part (this is only meant to draw attention to this change).

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.

Include variable in Django template loop

I have a for loop in a Django template, which prints out a list of books, which works well. The issue comes when I try to mark one of the items in the list as selected, based on a value passed in from the views.py file:
<select name="b">
<option value="1">Book</option>
{% for book in books %}
<option {% if book.id == selected_book %} selected {% endif %} value="{{ book.id }}">{{ book.t }}</option>
{% endfor %}
</select>
The "books" variable is a list, passed in from the views.py file. I can access these variables fine outside of the loop, but if I try to include a seperate variable inside the loop ("selected_book"), I have issues.
The above code does nothing, and if I try to wrap the variable in double brackets
{{ selected_book }}
I get the following error:
TemplateSyntaxError
Could not parse the remainder: '{{' from '{{'
The variable is being passed into the template, because I can get it to print to the page. I only get an error when I try to use it in the for loop.
If I write "{% if book.id == 2 %}" that works fine.
make sure that selected_book is an integer not a string, otherwise the code is fine

Jinja2 to put a whole element in <option>

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 ...)

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!

Categories

Resources