Value iteration in HTML - html

Description
I want to make this view work,
I'm using a loop for this table, I managed to do a loop for the input part of the id.
The input id has followed the increment according to the number of iterations
Problem
However, I also want variables like input id to apply in the value input.
Ex,
Iteration 1 > <input id="id-sensor-1" type="text" value="{{ variable-loopindex1 }}">
Iteration 2 > <input id="id-sensor-2" type="text" value="{{ variable-loopindex2 }}">
Iteration 3 > <input id="id-sensor-3" type="text" value="{{ variable-loopindex3 }}">
I'm using Python Flask and HTML Template. How do I get the conditions I want to work? Or is there any other solution? I'm at a loss to search for the keywords. Thanks

Store variables in an iterable object, such as variables:
{% for variable in variables %}
<input id="id-sensor-{{loop.index0}}" type="text" value="{{ variable }}">
{% endfor %}

Related

how to name numerous dynamic input fields for post method - Django

In my online shop, I fetch all of the products and services from two different apps and list them for the user to make his wishlist.
Each product or service is displayed in a bootstrap card that contains an input field for the count of products.
#views.py
def my_products(request):
ip_sensor = Ip_sensor.objects.all().order_by('title')
control_valves = ControlValves.objects.all().order_by('title')
context = {
'ip_sensor': ip_sensor,
'control_valves': control_valves,
}
return render(request, 'users/basket/my_products.html', context)
then in the template, they are being displayed in this way:
<form method="post" id="add_to_wishlist" data-url="{% url 'my_products' %}">
{% csrf_token %}
{% if ip_sensor %}
{% for item in ip_sensor %}
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-12">
<p class="card-text text-center text-capitalize">{{ item.title }}</p>
</div>
<div class="col-12">
<div class="form-group">
<input type="hidden" name="tag" value="{{ item.type }}"> <!-- what to put in name field of this line -->
<input type="hidden" name="item_id" value="{{ item.id }}"> <!-- what to put in name field of this line -->
<label for="count" class="control-label">count</label>
<input type="text"
id="count"
name="count" <!-- what to put in name field of this line -->
placeholder="Count"
class="form-control"
autofocus/>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</form>
Question:
When I return the count of each product or service through a POST method back to my views.py to save to his wishlist, I don't know how to distinguish between the returned values??
Since items are being displayed in a for loop and I want to save each of the selected items separately in a WishListItem object (model), I need to name each card's input fields separately but I don't know how to do it.
I can save each item in this way:
if request.method == 'POST':
owner = request.user
count = request.POST.get('count')
tag = request.POST.get('tag')
object_id = request.POST.get('item_id')
wishlist = WishListItem(owner=owner,
content_type=class_types[tag],
object_id=object_id,
tag=tag,
count=count)
wishlist.save()
return redirect('my_products')
When there are multiple inputs with same name, request.POST has list of all those input element values. So, you can get all item ids using request.POST.getlist('item_id') and it will return list containing all ids. In your html you can name all other inputs using id as part of the name attribute, like this:
...
<input type="hidden" name="tag_{{ item.id }}" value="{{ item.type }}"> <!-- item id has become part of the input name -->
<input type="hidden" name="item_id" value="{{ item.id }}"> <!-- all item ids will be accessed as list in view -->
<label for="count" class="control-label">count</label>
<input type="text"
id="count"
name="count_{{ item.id }}" <!-- item id has become part of the input name -->
placeholder="Count"
class="form-control"
autofocus/>
...
And in your view you can access all values like this:
...
for object_id in request.POST.getlist('item_id'): #this will contain a list with all item ids in it
count = request.POST.get('count_%s'%object_id) #as html inputs are named with ids as part of name you can access them
tag = request.POST.get('tag_%s'%object_id) #as html inputs are named with ids as part of name you can access them
wishlist = WishListItem(owner=owner,
content_type=class_types[tag],
object_id=object_id,
tag=tag,
count=count)
wishlist.save()
...
I found the answer based on #datosula's answer.
since the product id may be repetitive because products are loaded from various tables, then a unique tag is required to distinguish returned values in views.py. I mixed up product's title and products type to achieve this:
<div class="form-group">
<input type="hidden" name="title_type" value="{{ item.title }}{{ item.type }}">
<input type="hidden" name="item_id_{{ item.title }}{{ item.type }}" value="{{ item.id }}">
<input type="hidden" name="tag_{{ item.title }}{{ item.type }}" value="{{ item.type }}">
<input type="hidden" name="title_{{ item.title }}{{ item.type }}" value="{{ item.title }}">
<div class="text-center">
<input type="number"
id="count"
name="count_{{ item.title }}{{ item.type }}"
placeholder="count"
class="form-control"
value="0"
min="0"
max="9999"
autofocus/>
</div>
</div>
in views.py I got the values and created the object like the following:
....
for item in request.POST.getlist('title_type'):
object_id = request.POST.get('item_id_%s'%item)
tag = request.POST.get('tag_%s'%item)
print('\ntag: ', tag )
print('\nclass_types[tag]: ', class_types[tag])
count = request.POST.get('count_%s'%item)
title = request.POST.get('title_%s'%item)
if count != '0': # only save those products that their count is not 0
wishlist = WishListItem(owner=owner,
content_type=class_types[tag],
object_id=object_id,
tag=tag,
count=count,
title=title)
wishlist.save()
....
wish it helps somebody

Form not posting all checked input checkboxes

I am trying to post all checked input checkboxes. The input field is generated by django's for loop as shown below.
From what I have found so far, the below should be working. I believe the issue may be in the fact that the input fields are generated through the forloop, if so, how can I get around this? For each value add to list and post with js?
index.html
{% for q in list %}
{% if forloop.last %}
<form method="POST" name="selectedchecks"> {% csrf_token %}
<div class="qblock">
<label class="pure-material-checkbox">
<input class="selectedchecks" type="checkbox" name="choices[]" value="{{ q }}">
<span>
<p>{{ q }}</p>
</span>
</label>
</div>
</form>
{% endif %}
{% endfor %}
views.py
if request.method == 'POST':
selected_list = request.POST.getlist('choices[]')
What happens is that only the first value of {{ q }} is returned if the first checkbox is selected, if any other checkbox apart from the first is selected, nothing is returned (empty list). Selecting all checkboxes also only returns the first value.
It should POST all selected checkbox values.
Any help is appreciated!
UPDATE
The problem was that the form was being re-initialized for every loop iteration. Setting the <form> tag before the loop fixed the issue!

Set key,values for iteritem in for loop

How can I iterate over the element {{ dict.r0t0p1 }} using the for-loops I have established?
The desired end result of the <input.. line is next. In the example line the key is r0t0p1, and I need the corresponding value, where in this case the loop value of both r and t are 0, but they change for each input line.
<input type="text" id="r0t0p1" name="r0t0p1" value="{{ dict.r0t0p1 }}"></input>
So the same values of r and t for the id and the name attributes are required for the dict key to produce the dict value.
{% for r in range(rounds)%}
{% for t in range(tables)%}
<input type="text" id="r{{r}}t{{t}}p1" name="r{{r}}t{{t}}p1" value="{{ dict.r0t0p1 }}"></input>
{%endfor%}
{%endfor%}
I tried using a set command to define cell but got the following error. So it looks like nesting loop indices won't work.
{% set cell = r{{r}}t{{t}}p1 %}
TemplateSyntaxError: expected token 'end of statement block', got '{'
Try this maybe:-
{% for r in range(rounds)%}
{% for t in range(tables)%}
{% set cell = 'r'+r|string+'t'+t|string+'p1' %}
<input type="text" id="{{ cell }}" name="{{ cell }}" value="{{ dic[cell] }}"></input>
{%endfor%}
{%endfor%}

How to draw inputs without the id attribute using WTForms?

In my flask application I have to draw a form multiple times on the same page. This leads to the problem where I have multiple input fields with the same id on the page. E.g.:
class ChannelForm(flask_wtf.Form):
name = StringField('name')
together with this template:
<form>
{{ form.name }}
</form>
...
<form>
{{ form.name }}
</form>
lead to two input elements with the same id:
<input id="name" name="name" value="" type="text">
Is there an official way to disable adding the id attribute?
Quick n' dirty:
I've found that the following works well: instead of using the field directly, I wrap them in a jinja macro:
{% macro render_field(field) %}
<label>
<span>{{ _field.label.text }} </span>
{{ field(id=False, **kwargs) }}
</label>
{% endmacro %}
which can be used like this:
{% from "_formhelpers.html" import render_field %}
{{ render_field(form.name) }}
The trick here is to pass id=False when rendering the field.
using the meta object:
_Auto = object()
class NoIdAttributeMeta(DefaultMeta):
"""
Surpresses rendering the `id' attribute.
"""
def bind_field(self, form, unbound_field, options):
"""
Raises TypeError in case 'id' is given as a positional arg when constructing a field.
If this happens, make this code smarter or pass `id' as a keyword arg.
"""
# we check `id' at rendering time and if it is still _Auto, do not render it
unbound_field.kwargs.setdefault('id', _Auto)
return super().bind_field(form, unbound_field, options)
def render_field(self, field, render_kw):
if field.id is _Auto:
field.id = False
return super().render_field(field, render_kw)
class MyForm(flask_wtf.Form):
Meta = NoIdAttributeMeta
or be pragmatic:
You could also add a different prefix to each instance of your form and therefore you'd have unique ids:
my_form = MyForm(prefix="form1")
pass
I think you can pass a custom id to the field constructor like this:
<form>
{{ form.name(id_='yourId') }}
</form>
...
<form>
{{ form.name(id_='yourId2') }}
</form>
You don't need id=False because you already can set id when you call render_field()
{% macro render_field(_field) %}
<label>
<span>{{ _field.label.text }} </span>
{{ _field(**kwargs) }}
</label>
{% endmacro %}
Usage:
{{ render_field(field, id=False) }}
Explaination:
Because you have ****kwargs**, you can make the id=False and that would be more dymanic. You can choose when to remove ID.
Hope this help for those who have googled this solution

Django template form within a table increasing the row height

So I'm rendering a template, including a table...and for one of the columns, the value is blank or contains a Delete button/form (depending on whether delete is possible).
Anyway, my issue is that if the Delete button is present the row height is twice that of the others, making my table look rather ugly.
{% if condition %}
<td>
<form name="input" action="./delete/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="submit" name={{item}} value="Delete">
<input type="hidden" name="filter_start" value={% if date1 %}{{date1}}{% endif %}>
<input type="hidden" name="filter_end" value={% if date2 %}{{date2}}{% endif %}>
</form>
</td>
{% else %}
{% endif %}
Is there anything clearly wrong with the above? The "hidden" bits are so that I can retrieve certain 'dates' with the 'delete' button.
Try to add style="display:inline;" on the form.