I have a Flask template that displays a page with a dropdown list of owners, a table with the owner's win-loss record, and a radio to toggle between regular season record and playoff record.
The desired workflow is:
- If navigated to the page through the navigation bar, it should default to
/matchup-history/regular. (this works) - Else it should route accordingly whenever the
radiois toggled. (this doesn't work)
matchup-history.html
{%- extends "base.html" -%}
{% block nav_matchups %}active{% endblock %}
{%- block content -%}
<form action="{{ url_for('show_matchup_history', matchup_type=request.form['matchup_type']) }}" method="post">
<label>
<select name="owner_id" onchange="this.form.submit()">
{%- for o in owners %}
{%- if request.form['owner_id'] == o['owner_id']|string() %}
<option value="{{ o['owner_id'] }}" selected>{{o['first_name'] + " " + o['last_name'] }}</option>
{%- else %}
<option value="{{ o['owner_id'] }}">{{o['first_name'] + " " + o['last_name'] }}</option>
{%- endif %}
{%- endfor %}
</select>
</label>
{% block matchup_type_radio %}{% endblock %}
</form>
{%- if records|length > 0 %}
<div class="stats-table">
<table>
<tr>
{%- for th in table_headers %}
<th>{{ th }}</th>
{%- endfor %}
</tr>
{%- for r in records %}
<tr>
{%- for cn in column_names %}
<td>{{ r[cn] }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table>
</div>
{%- endif %}
{% endblock -%}
matchup-history/regular.html
{%- extends "matchup-history.html" -%}
{% block matchup_type_radio %}
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()" checked>Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()">Playoffs</label>
{% endblock %}
matchup-history/playoffs.html
{%- extends "matchup-history.html" -%}
{% block matchup_type_radio %}
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()">Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()" checked>Playoffs</label>
{% endblock %}
app.py
@app.route('/matchup-history/<string:matchup_type>', methods=['GET', 'POST'])
def show_matchup_history(matchup_type):
table_headers = ["Opponent", "Wins", "Losses"]
column_names = ["opponent_owner_name", "wins", "losses"]
owners = queries.get_owners()
if request.method == 'POST':
owner_id = request.form['owner_id']
else:
owner_id = owners[0]['owner_id']
if matchup_type == REGULAR_SEASON:
records = queries.get_matchup_history_regular(owner_id)
else:
records = queries.get_matchup_history_playoffs(owner_id)
return render_template("matchup-history/{matchup_type}.html".format(matchup_type=matchup_type),
title='Matchup History', table_headers=table_headers, column_names=column_names,
owners=owners, records=records)
The page correctly loads /matchup-history/regular when clicked on, but fails whenever the radio button is toggled:
127.0.0.1 - - [20/Sep/2018 08:32:53] "GET /matchup-history/regular HTTP/1.1" 200 -
127.0.0.1 - - [20/Sep/2018 08:32:56] "POST /matchup-history/ HTTP/1.1" 404 -
It seems like request.form['matchup_type'] is empty when matchup-history.html is rendered, so submitting the form will not have the desired effect. How can I refactor to route url_for to different matchup_type?
Edit: Per @Joost's suggestion, I rethought the design.
matchup-history.html
{%- extends "base.html" -%}
{% block nav_matchups %}active{% endblock %}
{%- block content -%}
<form action="{{ url_for('show_matchup_history') }}" method="get">
<label>
<select name="owner_id" onchange="this.form.submit()">
{%- for o in owners %}
<option value="{{ o['owner_id'] }}" {%- if o['owner_id'] == selected_owner %} selected {% endif %}>{{o['first_name'] + " " + o['last_name'] }}</option>
{%- endfor %}
</select>
</label>
<label><input type="radio" name="matchup_type" value="regular" onclick="this.form.submit()" {%- if matchup_type == "regular" %} checked {% endif %}>Regular Season</label>
<label><input type="radio" name="matchup_type" value="playoffs" onclick="this.form.submit()"{%- if matchup_type == "playoffs" %} checked {% endif %}>Playoffs</label>
</form>
{%- if records|length > 0 %}
<div class="stats-table">
<table>
<tr>
{%- for th in table_headers %}
<th>{{ th }}</th>
{%- endfor %}
</tr>
{%- for r in records %}
<tr>
{%- for cn in column_names %}
<td>{{ r[cn] }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table>
</div>
{%- endif %}
{% endblock -%}
base.html
...
<a href="{{ url_for('show_matchup_history') }}" class="{% block nav_matchups %}{% endblock %}">Matchups</a>
...
app.py
@app.route('/matchup-history', methods=['GET'])
def show_matchup_history():
table_headers = ["Opponent", "Wins", "Losses"]
column_names = ["opponent_owner_name", "wins", "losses"]
matchup_type = request.args.get('matchup_type', default="regular")
owner_id = request.args.get('owner_id', type=int)
owners = queries.get_owners()
if not owner_id:
owner_id = owners[0]['owner_id']
if matchup_type == REGULAR_SEASON:
records = queries.get_matchup_history_regular(owner_id)
else:
records = queries.get_matchup_history_playoffs(owner_id)
return render_template("matchup-history.html".format(matchup_type=matchup_type),
title='Matchup History', table_headers=table_headers, column_names=column_names,
matchup_type=matchup_type, selected_owner=owner_id, owners=owners, records=records)
Flow is now:
- Clicking on
Matchupsfrom navbar will route to/matchup-historyand default to showing regular season matchups - Clicking on
Playoffsradio will route to/matchup-history?matchup_type=playoffs&owner_id=12345 - Clicking on
Regularradio will route to/matchup-history?matchup_type=regular&owner_id=12345 - Clicking on a different owner in the
dropdownwill route to/matchup-history?matchup_type=regular&owner_id=98765