Skip to content
Advertisement

Python | Flask, using request.form in a class to POST data and update Jinja Template

I am building a small app using a forex converter api, it’s function is to take one currency, and convert a value into the new currency. I seem to be getting caught when accessing my class “Survey” everything I try to get data from my html form. My program is getting caught on self.convertFrom=request.form[‘convertFrom’] and the python debugger is giving me “RuntimeError: Working outside of request context.” I would greatly appreciate if someone can show/explain to me what it is im doing wrong here.

app.py

from flask_debugtoolbar import DebugToolbar
from forex_python.converter import CurrencyRates
from handleForm import Survey
app = Flask(__name__)
survey = Survey()
result=["Give me something to convert!"]

@app.route("/")
def home_page():
    """Loads home page where user can enter their first conversion"""
    return render_template('index.html')

@app.route("/conversion")
def show_conversion():
    """shows the users conversion"""
    return render_template('convSubmit.html', result=result)

@app.route("/conversion/new", methods=["POST"])
def add_conversion():
    """clear old conversion from list and add new"""
    result=[]
    result.append(survey.convertCurrency())
    return redirect("/conversion")

handleForm.py

from flask import Flask, render_template, request
from forex_python.converter import CurrencyRates
c = CurrencyRates()


class Survey():
    def __init__(self):
        self.convertFrom=request.form['convertFrom'] <---gets caught here
        self.convertTo=request.form['convertTo']
        self.value=request.form['value']
        

    def convertCurrency(self):
        currencyFrom = self.convertFrom
        currencyTo = self.convertTo
        getValue = int(self.value)
        result = c.convert(currencyFrom, currencyTo, getValue)
        return result

Advertisement

Answer

The request variable will be available only when a request is active. In simple terms it will be available only when it is invoked by a view function handling a route.

In your case, you are trying to initialise the survey object outside any root function. That line will be invoked when the app server is started, before any request has been reserved, and hence flask is throwing an error saying that you are invoking it outside of request context.

To fix it, you should move the survey = Survey() inside a view function

@app.route("/conversion/new", methods=["POST"])
def add_conversion():
    """clear old conversion from list and add new"""
    result=[]
    survey = Survey()
    result.append(survey.convertCurrency())
    return redirect("/conversion")

While this would fix the problem, it is still not a good pattern to make that class constructor to directly access the request global.

If you need the constructor itself to initialize these params, you can pass these as arguments to the constructor and then pass them when initializing

from flask import Flask, render_template, request
from forex_python.converter import CurrencyRates
c = CurrencyRates()


class Survey():
    def __init__(self, convertFrom, convertTo, value):
        self.convertFrom=convertFrom <---gets caught here
        self.convertTo=convertTo
        self.value=value
        

    def convertCurrency(self):
        currencyFrom = self.convertFrom
        currencyTo = self.convertTo
        getValue = int(self.value)
        result = c.convert(currencyFrom, currencyTo, getValue)
        return result

And then change the view function to pass the values to the constructor

@app.route("/conversion/new", methods=["POST"])
def add_conversion():
    """clear old conversion from list and add new"""
    result=[]
    survey = Survey(request.form["convertFrom"], request.form["convertTo"], request.form["value"])
    result.append(survey.convertCurrency())
    return redirect("/conversion")
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement