Reputation: 15620
I have spent some time on this but cannot figure out the exact cause of the following behaviour.
I have a Django form and in the template I am trying to see if an integer is present in a list and then doing something with it.
{% if pk in form.area.value %} {# form.area.value is a list like [7,21] #}
do something
{% endif%}
Everything works fine except in cases where the form is reloaded after a validation error. In such cases, the list that I am comparing with, gets converted to list of strings (from a list of ints) on its own and the if
test fails. So [7,21]
above becomes ['7','21']
In case it helps, this is how the form is being rendered in the view:
On the GET request (where the if condition works fine):
form = SchoolForm(instance = school)
return render(request, 'edit-school.html', {'form': form, 'school_id': school_id})
After the POST request (where the if condition fails in the template):
form = SchoolForm(request.POST or None, instance=school, request=request)
return render(request, 'edit-school.html', {'form': form, 'school_id': school_id})
Update: Got it to work by converting string values after the POST request in the form back to int by declaring another method in the form (as suggested by @bruno in the answer below) and using it in the template. Here's the code snippet (of how its being used in the template):
<div class="checkbox">
{% for pk, choice in form.area.field.widget.choices %}
<label for="id_{{sub_type}}_{{form.area.name}}_{{ forloop.counter0 }}">
<input class="form-control" id="id_{{sub_type}}_{{form.area.name}}_{{ forloop.counter0 }}" name="{{form.area.name}}" type="checkbox" value="{{ pk }}" {% if pk in form.area_values %} checked="checked" {% endif %}/>
<span class="badge">{{ choice }}</span>
</label>
{% endfor %}
</div>
Upvotes: 2
Views: 411
Reputation: 77902
After the user submitted the form, {{ form.area.value }}
(which in Python resolves to form["area"].value
) is populated with the raw data from request.POST
, which are indeed strings.
You didn't clearly explain what kind of "fancy thing" you're trying to do in the template so it's hard to come with a "best" solution for your use case, but as a general rule, templates are not the place for anything fancy - that's what Python is for (either in your view, in your form, in a custom templatetag or filter etc).
A very quick and simple solution would be to add a method to your form that returns the area
boundfield values as ints:
class SchoolForm(forms.ModelForm):
# your code here
def area_values(self):
# XXX this might require some conditionals or
# error handling to be failsafe
# works with both python 2.x and 3.x
return [int(v) for v in self["area"].value()]
then in your template, replace {% if pk in form.area.value %}
with {% if pk in form.area_values %}
Upvotes: 3