Колба, передающая значение request.form в url_for - PullRequest
0 голосов
/ 20 сентября 2018

У меня есть шаблон Flask, который отображает страницу со списком dropdown, равным owners, table с записью проигрыша владельца и radio для переключения между regular записью сезона и playoff запись.

Требуемый рабочий процесс:

  1. Если при переходе на страницу через панель навигации по умолчанию используется значение /matchup-history/regular.(это работает)
  2. В противном случае он должен маршрутизироваться соответствующим образом при каждом переключении radio.(это не работает)

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 / регулярно.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 %}

история матчей / 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)

Страницакорректно загружает /matchup-history/regular при нажатии, но не срабатывает всякий раз, когда переключается переключатель:

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 -

Кажется, что request.form['matchup_type'] пусто при отображении matchup-history.html, поэтому отправка формы не будет иметьжелаемый эффект.Как я могу выполнить рефакторинг для маршрутизации url_for на другие matchup_type?

Редактировать: За @ Joost Предложение, я переосмыслил дизайн.

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)

Поток теперь:

  1. Нажатие на Matchups с навигационной панели приведет к /matchup-history и по умолчанию показывает совпадения регулярного сезона
  2. НажатиеPlayoffs радио будет направлено на /matchup-history?matchup_type=playoffs&owner_id=12345
  3. При нажатии на Regular радио будет направлено на /matchup-history?matchup_type=regular&owner_id=12345
  4. При нажатии на другого владельца в dropdown будет направлено на /matchup-history?matchup_type=regular&owner_id=98765

1 Ответ

0 голосов
/ 20 сентября 2018

Итак, сейчас вы пытаетесь получить доступ к request.form в запросе get.Тем не менее, form всегда будет пустым в запросе get, потому что такова природа запроса get.Таким образом, только когда вы получите доступ к маршруту @app.route('/matchup-history/<string:matchup_type>' через почтовый запрос, он сможет правильно перенаправить.

Этот работающий miniapp хорошо отображает это:

from flask import Flask, render_template_string, request
app = Flask(__name__)

TEMPLATE_STRING = """
    <form action="{{ url_for('index') }}" method="post">
    {{request.form['matchup_type']}}<br><br>
    <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>
    </form>
"""


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return render_template_string(TEMPLATE_STRING)
    else:
        return render_template_string(TEMPLATE_STRING)

ПервыйКогда вы открываете страницу, вы видите только переключатель.Но как только вы нажмете на переключатель, он поместит форму, и поэтому вы увидите выбранное значение в верхней части страницы.Если вы нажмете еще раз, вы снова отправите форму и т.д.Я думаю, что нет необходимости делать запрос POST с этой формой, потому что вы не обновляете какие-либо данные, вы просто запрашиваете.

    from flask import Flask, render_template_string, request
app = Flask(__name__)

TEMPLATE_STRING = """
    <form action="{{ url_for('history') }}" method="get">
    <select name="owner_id">
    {% for owner in owners %}
      <option {% if owner['id'] == selected_owner_id %} selected {% endif %}value="{{owner['id']}}">{{owner['name']}}</option>
     {% endfor %}
    </select>
    <label><input type="radio" name="matchup_type" value="regular" {%if selected_matchup_type == 'regular'%}checked{%endif%} onclick="this.form.submit()">Regular Season</label>
    <label><input type="radio" name="matchup_type" value="playoffs" {%if selected_matchup_type == 'playoffs'%}checked{%endif%} onclick="this.form.submit()"  >Playoffs</label>
    <br>Queried data goes here
    </form>
"""
owners = [{'id': 1, 'name': 'bob'}, {'id': 2, 'name': 'gary'}, {'id': 3, 'name': 'tom'}]
matchup_types = 'regular', 'playoffs'


@app.route('/history', methods=['GET'])
def history():
    owner_id = request.args.get('owner_id', None, type=int)
    if owner_id not in [owner['id'] for owner in owners]:
        owner_id = owners[0]['id']
    matchup_type = request.args.get('matchup_type', None)
    if matchup_type not in matchup_types:
        matchup_type = matchup_types[0]
    # now you know the owner_id and the matchup type, and know that both are valid, do some query to get table data
    return render_template_string(TEMPLATE_STRING, owners=owners,
                                  selected_owner_id=owner_id,
                                  selected_matchup_type=matchup_type,
                                  matchup_types=matchup_types)

Я думаю, что это то, что вам нужно.Форма никогда не публикуется, всегда ставится как запрос на получение (<form action="{{ url_for('history') }}" method="get">).Если значения отсутствуют или недействительны, мы по умолчанию возвращаемся к некоему типу owner / matchup_type.Проверенные значения запоминаются и используются для визуализации шаблона.

Это помещает всю логику фляги в @app.route, а всю логику дзиндзя - в шаблон.

Некоторые общие замечания:

Я думаю, что доступ к request в jinja не предпочтителен, потому что jinja по-разному обрабатывает ошибки / пропущенные значения, и если они являются результатом логики, связанной с вашим запросомСтановится трудно угадать, что происходит.Так что разберитесь с входящим запросом на стороне Python.

Вместо того, чтобы переносить 2 радиоблока в зависимости от выбранного значения, просто используйте один блок и проверьте в опциях, какой из них вам нужен.<option {% if some_value == some_other_value %} checked {% endif%}>blabla</option>.

Сделайте намного больше проверки ввода!В вашем первом примере имя вашего шаблона определяется по некоторому введенному пользователем значению (тип соответствия).Но что, если пользователь публикует несуществующее значение?Вы получаете ошибки.

Если единственное различие между двумя шаблонами состоит в том, какой переключатель выбран, вам не нужны два шаблона.Смотрите обновленную версию, как просто справиться с этим в одном шаблоне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...