WTforms IntegerField in fieldlist never validates using manual iteration - python

I have an InterField, that validates if a number is between the values 0 and 99. For some reason it never validates.
I have a feeling it is related to the FieldList and ther way I iterate over it in the template, but can't seem to get it working.
The form:
class dpiaImpactAnalysisForm(Form):
severity_score = IntegerField("Severity Score"),
validators=[NumberRange(min=0, max=99, message="Please provide a valid number")]))
identifiability_score = IntegerField("Identifiability Score"),
validators=[NumberRange(min=0, max=99, message="Please provide a valid number")]))
class dpiaThreatAnalysisForm(Form):
impact = FieldList(FormField(dpiaImpactAnalysisForm), min_entries=1)
In views I append the entries dynamically as required:
#app.route('/dpia/analysis/<project_id>', methods=["GET", "POST"])
def analysis(project_id):
form = dpiaThreatAnalysisForm()
prim = Assets.query.filter_by(selected=True, primary=True).all()
primary_assets = list(map(vars, prim))
ev = Events.query.all()
events = list(map(vars, ev))
# add fields to the form...
for z in range(len(prim) * len(ev)):
form.impact.append_entry()
supp = Assets.query.filter_by(selected=True, primary=False).all()
supporting_assets = list(map(vars, supp))
ths = Threats.query.all()
threats = list(map(vars, ths))
# add fields to the form
for z in range(len(ths) * len(supp)):
form.likelihood.append_entry()
if form.is_submitted():
print "submitted"
if form.validate():
print "valid"
print form.errors
if form.validate_on_submit():
# This is never printed:
app.logger.info("success!!")
pprint(form.likelihood)
return redirect(url_for(next_step, project_id=project_id))
return render_template('analysis.html', form=form, threats=threats, supporting_assets=supporting_assets, primary_assets=primary_assets, events=events)
In the template I iterate over a list primary_assets in a list events, and add the fields per iteration:
{% for val in events %}
{% if not counter or loop.index0 == 0 %}
{% set counter = [] %} <!-- loop hack !-->
{% endif %}
<strong>Event: {{ val.name }}</strong><br />
Jeopardizes: {{ val.jeopardizes }}<br />
{% for pa in primary_assets %}
<strong>{{ pa['name'] }}</strong><br />
{{ form.impact[counter|length].identifiability_score(placeholder='') }} <br />
{{ form.impact[counter|length].severity_score(placeholder='') }}
{{ form.impact[counter|length].hidden_tag() }}
{% if counter.append('1') %}{% endif %}
{% endfor %}
{% endfor %}
The hidden_tag() doesn't work either. Normally I iterate of the forms with with something like
{% for impact in form.impact %}
{{ impact.form.hidden_tag() }}
# do cbg
{% endfor %}
and that works, that's why I believe it's my manual looping that spoils it...
EDIT 2 march, 17:26
After some testing, I found that using
severity_score = IntegerField("Severity Score", validators=[Optional(), NumberRange(
min=0, max=9999999999, message="Please provide a valid number")])
works (if I set min=50 I get an error when inserting a number below 50), however, the CSRF is still not getting passed.
{{ form.impact[counter|length].hidden_tag() }} or
{{ form.impact[counter|length].form.hidden_tag() }} both don't work :(
I'm getting: {'impact': [{'csrf_token': ['CSRF token missing']}, {'csrf_token': ['CSRF token missing']}]}
EDIT 18:22
It seems that this: Form validation fails due missing CSRF is the solution. Investigating...

This: Form validation fails due missing CSRF is the solution.
In previous versions this wasn't needed, and after an installation of a new extension pip updated flask-wtf as well...

Related

form.as_hidden doesn't pass values to POST

My form has initial values in it. I use form.as_hidden to hide the values and pass those values through a POST request. However, the hidden values are not passing through. Is there a way through this?
views.py
def car_detail_view(request, id):
if request.method == "POST":
form = CarForm(request.POST)
print(form.is_valid())
if form.is_valid():
car_save = form.instance
get_car = Car.objects.get(number_plate=car_save.number_plate)
get_car.available = False
get_car.save()
return redirect('/')
else:
print(form.errors)
else:
car = Car.objects.get(id=id)
form = CarForm(initial={'brand':car.brand, 'number_plate':car.number_plate, 'price':car.price,
'available':car.available})
args = {
'car':car,
'form':form
}
return render(request, 'map/confirmation.html', args)
confirmation.html
<h1>Confirmation of Booking</h1>
{% block content %}
<p>Brand: {{ car.brand }}</p>
<p>Number Plate: {{ car.number_plate }}</p>
<p>Price: {{ car.price }}</p>
<p> Are you sure you want to book? <p>
<form class="" method="post">
{% csrf_token %}
{{ form.as_hidden }}
<input type="submit" value="Book {{ car.brand }}">
</form>
{% endblock %}
Error
<ul class="errorlist"><li>brand<ul class="errorlist"><li>This field is required.</li></ul></li><li>number_plate<ul class="errorlist"><li>This field is required.</li></ul></li><li>price<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
Django doesn't have a form.as_hidden method. Therefore {{ form.as_hidden }} will render as the empty string '' in your template.
You can use the as_hidden method for individual form fields.
{{ form.number_plate.as_hidden }}
If you use values from hidden fields, you might need to add code to prevent the user altering the field values (e.g. with their browser's developer tools). However, in your case you don't need to get the values from the form, you can fetch them from the database.
def car_detail_view(request, id):
if request.method == "POST":
car = Car.objects.get(id=id)
car.available = False
car.save()
return redirect('/')
else:
car = Car.objects.get(id=id)
args = {
'car':car,
}
return render(request, 'map/confirmation.html', args)
Once you've got this working, you might want to think about what happens if two users try to book the same car at once.

Values_list with flat=True still showing brackets

so I have this html code:
<legend><h1 > Weapons that this character has </h1></legend>
<div>
<ul style="list-style-type:none" >
{% if request.GET.idChar %}
<li >{{ charname }} Has Maihand {{ mh }} and Offhand {{ oh }}</li>
{% else %}
<li>no</li>
{% endif %}
</ul>
</div>
The issue is that {{ charname }}, {{ mh }} and {{ oh }} are still displaying the brackets after i added flat=True in their line in views.py, in fact they stopped showing the parenthesys, but still showing the brackets. I also tried named=True, named=bool, flat=bool. Also tried values instead of values_list...
Views.py:
def character_weapons (request):
idchar = request.GET.get('idChar')
weapons = Characterweapons.objects.filter(characterid__exact=idchar).values_list('weaponid','categoryid_id')
charname = Characters.objects.filter(characterid__exact = idchar).values_list('name', flat=True)
print("charname: ")
print(charname)
if weapons[0][1] == 1:
mh_id = weapons[0][0]
oh_id = weapons[1][0]
elif weapons[0][1] == 2:
oh_id = weapons[0][0]
mh_id = weapons[1][0]
mh = Weapons.objects.filter(weaponid__exact=mh_id).values_list('weaponname', flat=True)
oh = Weapons.objects.filter(weaponid__exact=oh_id).values_list('weaponname', flat=True)
context={"mh": mh, "oh": oh,"idchar": idchar,"charname": charname}
return render(request,'users/character_weapons.html', context)
If someone knows how to fix it please let me know.
Thanks in advance!
values_list() with flat=True returns a list of values, so you have to extract the value with an index of 0 since your queries appear to always return only one row:
context={"mh": mh[0], "oh": oh[0],"idchar": idchar,"charname": charname[0]}
It's a flat list, but it's still a list. If you want to output it in one go, use the |join filter.
{{ mh|join:"," }}

Flask-SQLAlchemy and GET requests with pagination

I'm trying to build a paginated search form for a simple site. My issue is this - when I navigate away from page 1 (via pagination), and execute or update a search, rather than returning to page 1, the form reloads on whatever page I happen to be on at the time. This breaks the display of the new set of results.
For example, if the URL is this, and I update the search and hit submit, I stay on page two rather than starting over at one.
mysite/coorddash/2?coord_status=Pending&start_date=01/23/2017&end_date=01/23/2018
# VIEWS
#app.route('/coorddash/<int:page>', methods=['GET', 'POST'])
def coordDash(page=1):
per_page = 3
existingISG = ISG.query \
.filter(or_(ISG.coordinator_status == 'IAT Verified', ISG.coordinator_status == 'New')) \
.order_by("isg.id desc") \
.paginate(page,per_page,error_out=False)
form=coordDashForm(request.args)
coordstatus=start=end=""
if form.validate():
coordstatus = request.values.get("coord_status")
form.coord_status.data = coordstatus
start = request.values.get("start_date")
form.start_date.data = datetime.strptime(start, '%m/%d/%Y')
end = request.values.get("end_date")
form.end_date.data = datetime.strptime(end, '%m/%d/%Y')
existingISG = ISG.query.filter(ISG.coordinator_status == coordstatus).filter(ISG.isg_created_on.between(start, end)).paginate(page,per_page,error_out=False)
return render_template('coorddash.html',
title = 'Coordinator Dashboard',
existingisg = existingISG,
form=form,
url_vals=request.query_string.decode())
#MODELS
class ISG(db.Model):
__tablename__ = 'isg'
id = db.Column(db.Integer, primary_key=True)
coordinator_status = db.Column(db.String(30), unique=False)
startdate = db.Column(db.DateTime)
enddate = db.Column(db.DateTime)
#HTML
<form action="" method="get" name="searchForm">
{{ form.coord_status.label }}:{{ form.coord_status }} | {{ form.sort_by.label }}:{{ form.sort_by }}<br>
{{ render_field(form.start_date) }}-{{ render_field(form.end_date) }}<br>
{{ form.submit }}
{{ form.csrf_token }}
</form>
{% for item in existingisg.items %}
<div>
<span>{{ item.location }}</span>
<span>{{ item.implementing_team }}</span>
</div>
{% endfor %}
{% if existingisg.has_prev %} Previous Page{% else %}No previous{% endif %} |
{% if existingisg.has_next %}Next Page {% else %}No more{% endif %}
It looks like you're passing back the pagination as a URL variable on reload of the page. Even with a new query, mysite.coorddash/2 is being sent to your coordDash method and you get the second page of results instead of the first.
If you change your form action to reference the current URL with a trailing /1 for the pagination, it should be sent to the correct view and pagination should restart. For example,
<form action={{ url_for('coordDash', page=1) }} method="get" name="searchForm">
The syntax may be slightly off, but something like this will send your results to the correct function for that URL and specify pagination.

Turbogears2 session management

In theory i did what i'm supposed to do in order to store some data in session variables but my controllers can't reach them. Here's the code:
#expose('')
#require(predicates.not_anonymous())
def savecustomer(self, customer=None, **kw):
if customer is None:
flash(_('Select a customer!'), 'error')
redirect('/')
customer = DBSession.query(Customer).filter_by(customer_id=customer).first()
session.delete()
session['customer'] = True
session['customer_id'] = customer.customer_id
session['customer_name'] = customer.customer_name
...
session.save()
and here is my view code:
{% if request.identity %}
{% if session['customer'] %}
<div class="customer"><i>{{ session['customer_name'] }}
{% if session['customer_type'] %} {{ session['customer_type'] }} {% endif %}
</i></div>
{% else %}
<div class="nocustomer">No customer selected</div>
{% endif %}
{% endif %}
and here's my "debugging":
for i in session.iterkeys():
print i
for i in session.itervalues():
print i
customer
customer_id
customer_name
True
3
Ciccio Pasticcio S.p.a.
and if i run the same code in another controller it gives me this:
_id
832f62d3bc5140c4a9f3ba36bc3e876a
What am i doing wrong? (this used to work until i "fixed" something else :) )
I solved the error by removing
session.delete()

Can Dynamic number of formset be used in a single view and passed o a single Template

I have the following view,template and form through which i am implementing the formset. I intend to implement multiple formsets in a single view/template but my number of formsets is dynamic based on user input. How can i have multiple dynamic number of formsets in this code?
Can i do this with dictionary element i.e by creating a dictionary of formsets??
My view is as follows:
def show (request):
b = request.session["s1"] # count of no of period ids
c = request.session["s2"] # account number inserted by user
d = request.session["s3"] # year inserted by customer
a = account_period.objects.filter(year=d).values('id')
e = account_period.objects.filter(year=d).values('month')
f = account_period.objects.filter(id = a).values('year')
butt = formset_factory(bu, extra=b)
if request.method == 'POST'
formset = butt(request.POST)
if formset.is_valid():
z = account_tab.objects.get(account_number=c)
pr = date.today()
i=0
for form in formset.forms:
x = form.cleaned_data['value']
y = account_period.objects.get(id=a[i:(i+1)])
try:
uip = budget.objects.get(account_no = c,account_period = a[i:(i+1)])
if uip.budget_amount != x
uip.budget_amount = x
uip.save()
except budget.DoesNotExist:
w = budget(account_no = z, account_period = y, budget_amount = x, created_by_login = 'me')
w.save()
i=i+1
pass
return HttpResponse('thanks')
form is
class bu(forms.Form):
value = forms.CharField()
template is
<html>
<head>
<title>BUDGET</title>
</head>
<body>
<p>BUDGET MANAGEMENTS</p>
<p>Your Account Number is : {{ account_number }}.</p> <p>You Chose {{ period }} {{month}} as period<p>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="." method="post">{% csrf_token %}
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
#
#rohan
my GET method return has many variables which has to be passed into template so i tried to pass the dictionary formsetlist (after appying the changes u suggested) in following 2ways
1)
formset = butt( return render_to_response('budgetfinalform.html', {'account_number': c,'period':d,'month':e,'year':f,'formset': formset},context_instance=RequestContext(request))
2)
ctx ={'formsetlist': formset}
formset = butt( return render_to_response('budgetfinalform.html', {'account_number': c,'period':d,'month':e,'year':f,ctx,context_instance=RequestContext(request))
but obtained "unboundlocalerror : local variable 'formset' referenced before assignment"
I would do something like:
def show (request):
#initial view processing
# fomset_count taken as parameter or user input
formsetlist = []
#create formset list
for i in range(0, formset_count):
formsetlist.append(formset_factory(bu, extra=b))
# other view related code
# for GET method
ctx = { 'formsetlist': formset }
return render_to_response('your_template_name', ctx,
context_instance = RequestContext(request)
)
In template:
<form action="." method="post">{% csrf_token %}
{% for formset in formsetlist %}
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
{%endfor%}
<input type="submit" value="Submit">

Categories