1

I am working on a Flask app constructed as follows:

  1. The starting HTML template, controlled by a view, displays a text box, where the user can enter a SQL request to request a SQLite database connected to the app.
  2. In a second view, the request is executed, then the result is converted into a pandas dataframe, then converted in HTML, then included into a second template where it is displayed on the screen.
  3. This second template has a form to select two columns to choose to build a plotly figure, displayed on a third template, controlled by a third view.

I do not understand how to use the pandas dataframe created in the second view within the third view, since the view uses render_template and not return. I succeeded once by storing the dataframe into the Flask session variable, but this is suitable for real small dataframes only. I tried to read the HTML version of the dataframe directly from the template, but I do not understand how to do either.

Here is the code for views.py:

@app.route("/", methods=["GET", "POST"])
def index():
    return render_template('base.html')

@app.route('/submit', methods=['POST'])
def submit():    
    request_recap = request.form.get('sqlr') # example : SELECT * FROM Soils

    with engine.connect() as conn:
        request_result = conn.execute(text(request_recap))
        columns = request_result.keys()
        request_result = request_result.fetchall()

    df = pd.DataFrame(request_result, columns=columns)

    # Here is the attempt with 'session' 
    session['df'] = df.to_json() 

    return render_template("result.html",
                            request_recap=request_recap,
                            request_result=df.to_html(index=False),
                            cols=df.columns)

@app.route('/plot', methods=["GET", "POST"])
def plot():
    # Here is the attempt with 'session', how to do better ?
    df = pd.read_json(session.get('df')) 

    x = request.form.get('var1')
    y = request.form.get('var2')
    fig = makefig(table=df, x=x, y=y)

    return render_template("plot.html",
                           fig=fig.to_html()) 
5
  • you have to preserve your data frame as "server-side session data" - that is not a given with flask / HTTP + HTML are stateless; which means you won't ordinarily have data generated in one request around when another request hits - Commented Sep 29 at 18:52
  • why do you need panda dateframe as it adds unnecessary complexity. As you said that you know only html & css, I guess you might not have known pandas Commented Sep 29 at 19:02
  • for ploting, you have used pandas? Commented Sep 29 at 19:05
  • I have done Python for a long time so I know pandas ; I used it by habit. I used plotly for plotting Commented Sep 29 at 19:16
  • every view is like separate program - one program doesn't have access to variables in other program, You may use file or database to send data from one program/view to another program/view. Problem is when it is used by many people at the same time. It needs extra information to inform which user saved these data. In web frameworks usually can sessions resolves this problem. Commented Sep 29 at 21:48

1 Answer 1

2

Actually render_template returns response to the user just like any other python function returns the result. Meaning: Once the response is rendered, all the local variables are destroyed.

This is without pandas DataFrame. Used plotly for plotting as you mentioned in the comment. No javascript.

views.py :


from flask import Flask as fl
from flask import render_template as rt
from flask import request as rq, session
from sqlalchemy import text
import plotly.graph_objects as go


app = fl(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'

@app.route("/", methods=["GET", "POST"])
def index(): return rt('base.html')

@app.route('/submit', methods=['POST'])
def submit():    
    request_recap = rq.form.get('sqlr')
    
    with engine.connect() as conn:
        request_result = conn.execute(text(request_recap))
        columns = list(request_result.keys())
        rows = request_result.fetchall()

    # Convert to list of dicts for template
    results_as_dicts = [dict(zip(columns, row)) for row in rows]

    return rt("result.html",
                          request_recap=request_recap,
                          request_result=results_as_dicts,
                          cols=columns)

@app.route('/plot', methods=["POST"])
def plot():
    # Get data from form
    sql_query = rq.form.get('sql_query')
    x_col = rq.form.get('var1')
    y_col = rq.form.get('var2')
    
    # Re-execute the same query
    with engine.connect() as conn:
        request_result = conn.execute(text(sql_query))
        columns = list(request_result.keys())
        rows = request_result.fetchall()

    # Create plot directly from raw data using Plotly
    fig = create_plot_from_raw_data(rows, columns, x_col, y_col)
    
    return rt("plot.html", fig=fig.to_html())

def create_plot_from_raw_data(rows, columns, x_col, y_col):
    """Create Plotly figure without pandas"""
    # Get column indices
    x_idx = columns.index(x_col)
    y_idx = columns.index(y_col)
    
    # Extract data
    x_data = [row[x_idx] for row in rows]
    y_data = [row[y_idx] for row in rows]
    
    # Create Plotly scatter plot
    fig = go.Figure()
    
    fig.add_trace(go.Scatter(
        x=x_data,
        y=y_data,
        mode='markers',
        marker=dict(
            size=8,
            color='blue',
            opacity=0.7
        ),
        name=f'{y_col} vs {x_col}'
    ))
    
    fig.update_layout(
        title=f'{y_col} vs {x_col}',
        xaxis_title=x_col,
        yaxis_title=y_col,
        template='plotly_white'
    )
    
    return fig
    

result.html :



    <p>Your Query: {{ request_recap }}</p>
    
    <!-- Display results as table -->
    <table>
        <thead>
            <tr>
                {% for col in cols %}
                <th>{{ col }}</th>
                {% endfor %}
            </tr>
        </thead>
        <tbody>
            {% for row in request_result %}
            <tr>
                {% for col in cols %}
                <td>{{ row[col] }}</td>
                {% endfor %}
            </tr>
            {% endfor %}
        </tbody>
    </table>
    
    <!-- Form for plotting -->
    <form action="/plot" method="POST">
        
        <input type="hidden" name="sql_query" value="{{ request_recap }}">
        
        <label for="var1">X-axis:
            <select name="var1" id="var1" required>
                <option value="">Select X column</option>
                {% for col in cols %}
                <option value="{{ col }}">{{ col }}</option>
                {% endfor %}
            </select>
        </label>
        
        <label for="var2">Y-axis:
            <select name="var2" id="var2" required>
                <option value="">Select Y column</option>
                {% for col in cols %}
                <option value="{{ col }}">{{ col }}</option>
                {% endfor %}
            </select>
        </label>
        
        <br><br>
        <button type="submit">Generate Plot</button>
    </form>
   

plot.html:


    
    <!-- Display the Plotly figure -->
    <div>
        {{ fig|safe }}
    </div>
    

Sign up to request clarification or add additional context in comments.

1 Comment

I adapted your example to my own code and it worked ! Many thanks ! (indeed, Flask does not seem appropriate for that kind of stuff)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.