I'm trying to cast a value from my template to the views with this code:
<form action="{% url 'view_passwordgenerator' %}">
<select name="length">
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12" selected="selected">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
</select> Length
<input type="submit" value="Generate Password" class="btn btn-primary">
</form>```
views
def view_passwordgenerator(request):
length = int(request.GET.get('length'))
for i in range(length):
...
return render(request, 'home/passwordgenerator.html')
This error appears:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
im just looking for a way to get the int out of the template without this error, maybe there is another way to cast it.
CodePudding user response:
Likely you render both the page with the form, and the page with the result when submitting that form with the same view.
As a result when you render that view for the first time, the length
will be missing, you thus should check and only cast it to an int
if we know it is part of the dictionary:
def view_passwordgenerator(request):
if 'length' in request.GET:
length = int(request.GET.get('length'))
for i in range(length):
# …
return render(request, 'home/passwordgenerator.html')
return …
THis however is still nog very elegant, since people can use the URL to inject data into request.GET
, and that is not per se an int. The most elegant way is likely to use a Django form:
from django import forms
class MyForm(forms.Form):
length = forms.IntegerField()
then you can check if the form validates:
def view_passwordgenerator(request):
form = MyForm(request.GET)
if form.is_valid():
for i in range(form.cleaned_data['length']):
# …
return render(request, 'home/passwordgenerator.html')
return …
You can render the picked item by passing it to the context:
def view_passwordgenerator(request):
if 'length' in request.GET:
length = int(request.GET.get('length'))
for i in range(length):
# …
return render(request, 'home/passwordgenerator.html', {'length': length})
return …
and then render this with:
<select name="length">
<option value="8" {% if length == 8 %}selected{% endif %}>8</option>
<option value="9" {% if length == 9 %}selected{% endif %}>9</option>
<option value="10" {% if length == 10 %}selected{% endif %}>10</option>
<option value="11" {% if length == 11 %}selected{% endif %}>11</option>
<option value="12" {% if length == 12 %}selected{% endif %}>12</option>
<option value="13" {% if length == 13 %}selected{% endif %}>13</option>
<option value="14" {% if length == 14 %}selected{% endif %}>14</option>
<option value="15" {% if length == 15 %}selected{% endif %}>15</option>
<option value="16" {% if length == 16 %}selected{% endif %}>16</option>
<option value="17" {% if length == 17 %}selected{% endif %}>17</option>
<option value="18" {% if length == 18 %}selected{% endif %}>18</option>
<option value="19" {% if length == 19 %}selected{% endif %}>19</option>
<option value="20" {% if length == 20 %}selected{% endif %}>20</option>
</select>
However I would advise to work with forms these can be used to render, validate, and clean data.