02/15/2018: python wtforms - handling dynamic fields
I wanted to have a web form with a variable number of fields - one for each day in a month. Since that number varies (i.e., Feb usually has 28, while Jan Jan has 31), I wanted my form to also have a variable number of input fields.
Naturally, I created a hack. The form has a constant 31 fields, but when displayed in the jinja2 template, only daysInMonth fields are used.
Here is the form definition:
from flask_wtf import FlaskForm
from wtforms import FieldList, HiddenField, IntegerField, StringField, SubmitField, validators
from wtforms.validators import DataRequired, UUID
class MonthForm(FlaskForm):
handle = HiddenField('handle', validators=[DataRequired(), UUID()])
month = HiddenField('month', validators=[DataRequired()])
year = HiddenField('year', validators=[DataRequired()])
daysInMonth = HiddenField('daysInMonth', validators=[DataRequired()])
for n in range(1, 32):
locals()[''.join("morning"+str(n))] = StringField('', [ validators.Length(min=0, max=4)])
locals()[''.join("evening"+str(n))] = StringField('', [ validators.Length(min=0, max=4)])
submit = SubmitField('Save')
export = SubmitField('Export')
def getField(self, fieldName):
for f in self:
if f.name == fieldName:
return f
return None
Note that I use a range to avoid the tedious, error-prone duplication of 64 fields. The locals() method is terrific.
The getField() method is needed in order to find the right field to display in the template.
{% for n in range(1, daysInMonth+1) %}
<tr>
<td>{{n}}</td>
<td>{{ form.getField('morning' + n|string)(size="5") }}</td>
<td>{{ form.getField('evening' + n|string)(size="5") }}</td>
</tr>
{% endfor %}
In a world in which python supports static class members, I’d use a hash to cache the fields. This would avoid the for loop every time a field is needed. On the other hand, the cache might be premature optimization. For my little, tiny application with less than 40 fields running the for loop is not a problem.
Footnote: Use raw and endraw inside {% %} tags to display Jinja2 code inside GitHub Markdown.
10/14/2017: Goodreads - Using Python To List To Read Shelf
I’ve been using http://goodreads.com for several years and have good substantial list of books on my To Read shelf. I thought it would be interesting to see how hard using the GoodReads API would be.
Not too difficult.
First I registered with GoodReads to get an API key. Then I ran the following curl command.
export GDKEY=XXX
curl --silent \
-o goodreads-to-read.xml \
"https://www.goodreads.com/review/list/32902953.xml?key=$GDKEY&v=2&shelf=to-read&per_page=200"
I created a small python script to handle reading the XML.
import xml.etree.ElementTree as etree
tree = etree.parse('/usr/src/app/goodreads-to-read.xml')
root = tree.getroot()
for child in root:
if child.tag == 'reviews':
for review in child:
for reviewElements in review:
if reviewElements.tag == 'book':
for bookElements in reviewElements:
if bookElements.tag == 'title':
print(bookElements.text)
The last step runs the script:
docker run \
--rm=true \
-v $(pwd):/usr/src/app \
python:3.6.3 \
python /usr/src/app/parsexml.py | head | sort
You could use python directly, of course, if you have it already installed.