0

I have two routes, the first one collects two variables that will be shown in the second route (template) by clicking submit. But if I write the URL from the second one (/viewtrips) on the browser then the two variables are not shown because they were never selected and stored in the global variables. So I want to prevent this. Is there any command e.g. a request?

The code for the first route '''

    @route('/', method=['GET', 'POST'])
    def homepage():
        if request.method == 'POST':
            planet = request.forms.get('destination')  # destination will be selected from a 
                  #dropdown menu and the click will be store and sent here
            dateTime = request.forms.get('date')
            global formDateTime   
            global formPlanet
            formDateTime = dateTime
            formPlanet = planet
   
            redirect('/viewtrips') #send us to the next page
        else:
          return template('templateHome')

'''

For the second one:

'''

@route('/viewtrips', method=['GET', 'POST'])
def viewTrips():

    global formPlanet
    global formDateTime
    flighttime = flightTime(formPlanet) #giving the variable to a function in another py file
    gifPlanet = gifplanet(formPlanet) # returns  a gif 
    planet = formPlanet
    datetime = formDateTime
    basePrice = planetPrice(formPlanet)
    if request.method == 'POST':
        seat =request.forms.get('seating')
        food = request.forms.get('food')
        global formSeat
        global formFood
        formSeat = seat  # values are stored in variables to insert them later in the database
        formFood = food
        redirect('/information')                

    return template('templateBooking', flighttime = flighttime, datetime = datetime, gifPlanet = gifPlanet, basePrice = basePrice, destination = planet)

'''

HTML for the first template:

'''

    <form method="POST">
        <label id="to">To:</label>
        <select id="destination" name="destination" required>
            <option value="" disabled selected>Choose aDestination</option>
            <option value="Mercury">Mercury</option>
            <option value="Venus">Venus</option>
            <option value="Mars">Mars</option>
            <option value="Jupiter">Jupiter</option>
            <option value="Saturn">Saturn</option>
            <option value="Uranus">Uranus</option>
            <option value="Neptune">Neptune</option>
        </select> 
        <label for="date" style="margin-left:15px">Date:</label>
        <input type="date" id="date" name="date" placeholder="Date" required>
        <input type="submit" value="submit">
        </form>

'''

For the second one:

'''

  <form method="POST">
    
    <p id="chooseseating">Choose your seating:</p>
    
    <input type="radio" id="seating" name="seating" value="Economy" required>
    <label for="seating1"> Economy Class ( +20M$ )</label><br>
    <input type="radio" id="seating" name="seating" value="Business" required>
    <label for="seating2"> Business Class ( +55M$ )</label><br>
    <input type="radio" id="seating" name="seating" value="First" required>
    <label for="seating3"> First Class ( +70M$ )</label>
    
    <p id="chooseseating">Include Food service?</p>
    
    <input type="radio" id="seating" name="food" value="Yes"required>
    <label for="food">Yes ( +2M$ )</label><br>
    <input type="radio" id="seating" name="food" value="No"required>
    <label for="food">No</label><br>
    
    <input type="submit" value="submit">
</form>
</div>

<div class="box22">
<form method="GET">
    <img id="solarsystem" src="{{gifPlanet}}" align="right">
</form>
</div>

'''

'''

 import bottle
 from bottle import run, template, route, request, redirect, static_file
 from requests import session
 from PlanetDestination import flightTime, gifplanet, price, planetPrice
 from database import dataInput,extractInfo, delete, editInfo, updateInfo, emailextraction
 from Passangers import init_db
 import PlanetsGif
 import json
 import bottle_session


app = bottle.app()
plugin = bottle_session.SessionPlugin(cookie_lifetime=600)
app.install(plugin)
#init_db()
#PlanetsGif.PlanetName_GIF()
#PlanetsGif.SolarSystem_GIF()

# global variables for future purposes



@route('/', method=['GET', 'POST'])
def homepage():
  if request.method == 'POST':
    planet = request.forms.get('destination')  
    dateTime = request.forms.get('date')
    session['destination'] = planet
    session['date'] = dateTime

    redirect('/viewtrips') #send us to the next page
else:
    return template('templateHome')

'''

ed190
  • 31
  • 7
  • Is the form being handled with the POST request on `route("/")` currently part of `templateHome`, or another page? My instinct would be to change this setup so that the POST actions for `route("/")` are instead handled directly within the route for viewtrips as the POST action there. If viewTrips is accessed via GET, it should go back to the "first" page. Then the current POST action on viewTrips should instead be handled within the route("/information") code as the POST condition there. – nigh_anxiety Jun 25 '22 at 02:27
  • @nigh_anxiety I edited my post so you can see my templates. The First one is templateHome and its route is "/". The second one is templateBooking and its route is "/viewtrips" – ed190 Jun 25 '22 at 09:00

1 Answers1

1

My recommendation would be to direct your forms to POST to the next page by using the action={{route}} attribute, instead of using a redirect. Then on each page that needs form info from the previous page, if the method was GET you redirect back to the home page.

I would also recommend moving away from globals in this case as well. That won't work if you could ever have two people accessing the website at the same time, as they would be overwriting each others values. One option is to keep the data you want to pass along within hidden fields on the form, and that's the solution I propose below. Otherwise, you could look into using bottle-session to store the user's current info within a session. This would act more like a global would keep the data from multiple users separate.

app.py

@route('/', method=['GET', 'POST'])
def homepage():
    return template('templateHome')
      

@route('/viewtrips', method=['GET', 'POST'])
def viewTrips():
    if method == "GET":
        redirect('/')
        
    # destination will be selected from a dropdown menu and the click will be store and sent here
    planet = request.forms.get('destination')  
    dateTime = request.forms.get('date')

    flighttime = flightTime(planet) #giving the variable to a function in another py file
    gifPlanet = gifplanet(planet) # returns  a gif 
    basePrice = planetPrice(planet)

    return template('templateBooking', flighttime=flighttime, datetime=dateTime, gifPlanet=gifPlanet, basePrice=basePrice, destination=planet)
    
@route('/information', method=['GET', 'POST'])
def information():
    if method == "GET":
        redirect('/')
    
    # seat and food were selected on viewTrips page
    # planet and dateTime were selected on homepage and passed as hidden fields.
    seat = request.forms.get('seating')
    food = request.forms.get('food')
    planet = request.forms.get('destination')  
    dateTime = request.forms.get('date')
    
    return template('templateInformation', destination=planet, food=food, seat=seating, datetime=dateTime)

templateHomepage form

<form method="POST" action="/viewtrips">
    <label for="destiniation" id="to">To:</label>
    <select id="destination" name="destination" required>
        <option value="" disabled selected>Choose a Destination</option>
        <option value="Mercury">Mercury</option>
        <option value="Venus">Venus</option>
        <option value="Mars">Mars</option>
        <option value="Jupiter">Jupiter</option>
        <option value="Saturn">Saturn</option>
        <option value="Uranus">Uranus</option>
        <option value="Neptune">Neptune</option>
    </select> 
    <label for="date" style="margin-left:15px">Date:</label>
    <input type="date" id="date" name="date" placeholder="Date" required>
    <input type="submit" value="submit">
</form>

templateViewTrips form

<form method="POST" action="/information">
    <!-- Keep needed trip details in hidden input fields -->
    <input type="hidden" id="destination" name="destination" value={{destination}}>
    <input type="hidden" id="date", name="date", value={{datetime}}>
    
    <p id="chooseseating">Choose your seating:</p>
    <input type="radio" id="seating" name="seating" value="Economy" required>
    <label for="seating1"> Economy Class ( +20M$ )</label><br>
    <input type="radio" id="seating" name="seating" value="Business" required>
    <label for="seating2"> Business Class ( +55M$ )</label><br>
    <input type="radio" id="seating" name="seating" value="First" required>
    <label for="seating3"> First Class ( +70M$ )</label>
    
    <p id="chooseseating">Include Food service?</p>
    
    <input type="radio" id="seating" name="food" value="Yes"required>
    <label for="food">Yes ( +2M$ )</label><br>
    <input type="radio" id="seating" name="food" value="No"required>
    <label for="food">No</label><br>
    
    <input type="submit" value="submit">
</form>
</div>

<div class="box22">
<form method="GET">
    <img id="solarsystem" src="{{gifPlanet}}" align="right">
</form>
</div>

Note - I didn't correct your viewTrips form where you have multiple fields using the same id and name, which appeared to be copy-paste errors. Also, it's not clear {{gifPlanet}} should be within a <form> as its non-actionable.

To use bottle-session, don't import from requests import session. requests.session is deprecated now anyway, but doing so was also overloading the reference session and causing problems.

Instead, after installing the plugin, you need to add session as a keyword parameter to each route that will access the session. Reference: https://pypi.org/project/bottle-session/

 import bottle
 from bottle import run, template, route, request, redirect, static_file
 # from requests import session
 from PlanetDestination import flightTime, gifplanet, price, planetPrice
 from database import dataInput,extractInfo, delete, editInfo, updateInfo, emailextraction
 from Passangers import init_db
 import PlanetsGif
 import json
 import bottle_session


app = bottle.app()
plugin = bottle_session.SessionPlugin(cookie_lifetime=600)
app.install(plugin)
#init_db()
#PlanetsGif.PlanetName_GIF()
#PlanetsGif.SolarSystem_GIF()

# global variables for future purposes



@route('/', method=['GET', 'POST'])
def homepage(session):
  if request.method == 'POST':
    planet = request.forms.get('destination')  
    dateTime = request.forms.get('date')
    session['destination'] = planet
    session['date'] = dateTime

    redirect('/viewtrips') #send us to the next page
else:
    return template('templateHome')
nigh_anxiety
  • 1,428
  • 2
  • 4
  • 12
  • Side note - I've worked more with Flask, so if anyone notices any subtle errors I made here due to differences in Flask and Bottle, please correct. – nigh_anxiety Jun 25 '22 at 15:29
  • Now i have a third route where all data is collected in a sql database and that's the "/information" route. I was using global variables to pass the information until '/information' was called. – ed190 Jun 25 '22 at 19:06
  • I would use a session for that, or just keep passing the info along the forms by using the hidden fields, then the information route can handle the Sql database and then redirect or display the correct template. Here's the problem with globals. Let's say 2 users are using the page simulataneously. User enters a destination and date on Homepage and submits. You put that info into the globals. Then while user 1 is on the View Trips page making their decision, user 2 submits the form on homepage with a different planet and date. That updates the globals to user 2's values. (continued) – nigh_anxiety Jun 25 '22 at 19:27
  • ....Then User 1 submits the form on the viewtrips page and it goes to information, when you get the global data to update the SQL table, you would have a mix of data from the two users, because the global variables are shared by all users. You have to isolate each users data by passing it along as part of the form or by using session data. – nigh_anxiety Jun 25 '22 at 19:29
  • Yes, I tried to do the first example of yours and I cannot store now the database but only the planet, seat, food and datime. Where could I find some explanation about sessions? I hate working with bottle but our tutor wants us do it with it. I can only find sessions' examples but for flask – ed190 Jun 25 '22 at 20:28
  • I don't know the bottle module that well, but it looks like there are two options. There's the `bottle-session` module https://pypi.org/project/bottle-session/ And then there's `Beaker` https://stackoverflow.com/questions/13735333/bottle-py-session-with-beaker https://github.com/bottlepy/bottle-beaker It looks like Beaker hasn't had any updates in 6 years, but maybe it just hasn't needed any. – nigh_anxiety Jun 25 '22 at 21:45
  • 'Now when I try to use' planet = request.forms.get('destination') ' and put it in ' session['destination'] = planet ' I get the error : 'function' object does not support item assignment – ed190 Jun 26 '22 at 08:50
  • which package are you using? it sounds like you have a function named session or a variable named session that was set to a callable instead of the expected dictionary. – nigh_anxiety Jun 26 '22 at 09:14
  • I updated my code on my post, so you can see it at the bottom. Python imported automatically this " from requests import session". If I delete that line I get: session['destination'] = planet NameError: name 'session' is not defined – ed190 Jun 26 '22 at 09:29
  • I added the keyword (session by default) to the routed method, but still getting an error that ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it – ed190 Jun 26 '22 at 10:55
  • So I tried with beaker and it worked, but I still dont know why didnt work with bottle-session – ed190 Jun 26 '22 at 11:53
  • WIth bottle-session, the problem was you imported `from requests import session`, where session is a deprecated function that returns an instance of the class Session, and then you overloaded by trying you use it directly as your session data. I'll add an update above instead of writing more clarification here – nigh_anxiety Jun 26 '22 at 14:34