Search code examples
pythonbottle

Evaluating user input before making a new database query


I am creating a small trivia game with Bottle and I am having some trouble. The page loads, a random trivia question is pulled from the database and appears in the browser, the server automatically attempts to grab the value from the form input when the page first loads, and the input is empty (no surprise there). But if I attempt to enter the answer to the trivia question in the input field, and click submit button, the page reloads, and it gets the next trivia question from the database. My user input never matches the current trivia question, because it is always holding the value to the previous question.

How do I get the value from the user input for that particular database query without the page reloading on submit and generating a new random query?

In my game.py file:

@app.route("/game", method=["POST"])
def game(db):
   db.execute("select * from questions order by rand() limit 1")
   data = db.fetchall()
   guess = ""
   name = ""
   for d in data:
      country_name = d["name"]

   if request.POST.the_guess:
      guess = request.POST.the_guess.strip()

return bottle.template("temp", data=data)

And in my temp.tpl:

<form method="POST" action="/game"> <input type="text" name="the_guess"> <input type="submit" value="guess"> </form>


Solution

  • Your request view does the same thing whether or not the user submits the form, i.e.

    • Get a random question
    • strip the response if provided.

    However, you have to consider two scenarios

    • User clicks on the link to "Start" playing the game and so has just landed on the page.
    • User has submitted the form and you must evaluate his reposne

    To do so, you must pass the question ID as a hidden field so you know what is the correct response.

    <form method="POST" action="/game">
        <input type="text" name="the_guess">
        <input type="submit" value="guess">
        <input type="hidden" name="qid" value="YOUR_QUESTION_ID">
    </form>
    

    The view code must therefore do something like this (I don't know correct semantics of a Bottle view, so consider this as pseudo-code):

    @app.route("/game", method=["POST", "GET"])
    def game(db):
       # Store if user answered last question correctly or not
       user_feedback = None
       # See if this view is beng invoked by user submitting an answer
       if "submit" in request.POST:
           guess = request.POST.the_guess.strip()
           qid = request.POST.qid
           # Lookup DB for answer of question with ID qid. Store it as answer
           if guess == answer:
               user_feedback = True
           else:
               user_feedback = False
       # This part will always execute
       db.execute("select * from questions order by rand() limit 1")
       data = db.fetchall()
       for d in data:
          country_name = d["name"]         
       return bottle.template("temp", data=data, user_feedback=user_feedback)
    

    Based on value of user_feedback, in your template you can display a "Correct!" or "Wrong :(" message.