UPDATE
After extra digging regarding my problem exposed below, I believe my difficulty in retrieving the data from a ListField of FormFields comes from the fact that I fail to validate the form. When I use form.validate_on_submit() instead of form.is_submitted() in the foundItem route I get the error message: TypeError: argument of type 'CSRFTokenField' is not iterable. Reading the documentation did not help me. If I don't validate the form, then I get the full html input tag from the FormField instead of the data.
--
I am trying to write a small inventory web application to learn about flask and MongoDB. So far I am just trying to implement the basic functionalities (create, update, delete). As a starting point my database contains only items with a part number and a quantity. I manage to add new documents to the database and I can retrieve a list of documents matching a part number. Each retrieved document is used to pre-fill a SearchedItemForm and this form is appended to a listField of a form SearchedItemListForm. This is done to be able to update the quantity of one or more elements at the same time in the same view. So far I have failed to implement the update and would appreciate any help. Here is the code and the logic.
The forms:
class SearchedItemForm(FlaskForm):
'''
Generic form for a single item returned from a search
in the searchItem page.
Note:
This class forms the building block of the class SearchedItemListForm.
'''
id_ = StringField('id', validators=[DataRequired()])
part_number = StringField('Part number', validators=[DataRequired()])
quantity = IntegerField('Quantity',validators=[DataRequired()])
class SearchedItemListForm(FlaskForm):
'''
Form consisting of a list of SearchItemForm. This is the form
that is passed to the searchItem page to display the found
items.
'''
items = FieldList(FormField(SearchedItemForm))
submit = SubmitField('Update')
The search is done from the searchItem route:
@app.route('/item/search', methods = ['GET', 'POST'])
def searchItem():
form = SearchForm()
if form.validate_on_submit():
query = {form.searchField.data:form.searchValue.data}
return redirect(url_for('foundItem', query=query))
return render_template('searchItem.html', title='Search item',
form=form)
From the search form I get a search field and a search value and a query is produced which is passed to the foundItem route.
@app.route('/item/result', methods = ['GET', 'POST'])
def foundItem():
query = json.loads(request.args.get('query').replace("'", "\""))
form, pnList = listOfSearchedItems(query)
if form.is_submitted():
for item in form.items:
print(item.quantity.data)
# some code to update db
return render_template('foundItem.html', title='Search result',
form=form, pnList=pnList)
The query is passed to the function listOfSearchedItems and a form of type SearchedItemListForm is pre-filled and returned together with a list of part numbers. Those parameters are passed to the foundItem template where they are shown and the quantity of any element can be changed. My difficulty is with the submission of the form. First of all, if I use if form.validate_on_submit() I get an error message TypeError: argument of type 'CSRFTokenField' is not iterable. Clearly there is something I don't understand with CSRF protection. More importantly I cannot get the quantity values as print(item.quantity.data) print the full html input tag instead of the quantity itself and this is where I would appreciate some help.
To be complete:
def listOfSearchedItems(query):
'''
return list of queried items from initial search
in the searchItem view.
Args:
query(dict): dictionnary for the query
Returns:
items(SearchedItemForm): form containing returned items
pnList: list of part numbers of returned items
'''
items = SearchedItemListForm()
pnList = []
results = mongo.db.optics.find(query)
for result in results:
item = SearchedItemForm()
item.id_.data = str(result['_id'])
item.part_number.data = result['part_number']
item.quantity.data = result['quantity']
pnList.append(result['part_number'])
items.items.append_entry(item)
return items, pnList
and the foundItem template
{% extends 'base.html' %}
{% block content %}
<h1>{{ title }}</h1>
{% if form.items %}
{% set pnList_id=0 %}
<form action="" method="post">
{{ form.hidden_tag() }}
<table>
<tr>
<th>Part number</th>
<th>Quantity</th>
</tr>
{% for item in form.items %}
<tr>
<td><a href="#">{{ pnList[pnList_id] }}</a></td>
<td>{{ item.quantity.data }}</td>
</tr>
{% set pnList_id=pnList_id+1 %}
{% endfor %}
</table>
{{ form.submit() }}
</form>
{% endif %}
{% endblock %}