pythonhtmlflaskroutes

How to get form data from input as variable in Flask?


I'm working on a simple UI to start and stop games by ID. The basic HTML I have written is as follows (game_id is populated by JS):

  <div align="center" class="top">
    <div align="left" class="game-id-input">
      Game ID: <input type="text" name="game_id" id="game_id">
    </div>

    <div align="right" class="buttons">
      <form action="{{ url_for('start_game', game_id=game_id) }}" method="get">
        <input type="submit" name="start" value="Start game" class="btn btn-success"></input>
      </form>
      <form action="{{ url_for('end_game', game_id=game_id) }}" method="get">
        <input type="submit" name="end" value="End game" class="btn btn-danger"></input>
      </form>
    </div>
  </div>

which looks like

input_and_buttons

I also have Flask route functions defined for each of the forms:

@app.route("/start_game/<game_id>")
def start_game(game_id):
    # ...

@app.route("/end_game/<game_id>")
def end_game(game_id):
    # ...

In my forms, how can I make game_id correspond to the game_id from #game_id?

Currently when I submit start and end games, I get a File Not Found error because it's just appending the literal <game_id> to the route.

I'm new to web development. This should be trivial, but I don't know what to search for. Sorry in advance for such a simple question.


Solution

  • You are trying to generate a url based on user input, but user input isn't available when Jinja is rendering the template on the server side, it's only available on the client side. So if you wanted to post to URLs with the game id as a URL parameter, you would have to build that URL on the client side with JavaScript.

    For what you're trying to do, that's not really necessary. You can get the submitted value of a named input with request.form['name']. Buttons are just like any other input, so you can name them to find out what action was taken.

    @app.route('/manage_game', methods=['POST'])
    def manage_game():
        start = request.form['action'] == 'Start'
        game_id = request.form['game_id']
        
        if start:
            start_game(game_id)
        else:
            stop_game(game_id)
    
        return redirect(url_for('index'))
    
    <form method="POST" action="{{ url_for('manage_game') }}">
        <input type="text" name="game_id"/>
        <input type="submit" name="action" value="Start"/>
        <input type="submit" name="action" value="Stop"/>
    </form>
    

    Even that's more verbose than you need. Given that you'd know if a game was already in progress, just toggle the current status instead of picking an action. It would never make sense to start a game that's already started, only stop it.