2

I have been working on a project in flask and I am stuck on one part where I need to figure out how to yield one flask template over another.

To illustrate what I mean, for example, I have a program like this.

main.py

from flask import Flask, stream_with_context, Response, render_template
app = Flask('app')

@app.route('/')
def hello_world():
    def generate():
        yield render_template('index.html')
        yield render_template('index2.html')
    return Response(stream_with_context(generate()))

app.run(host='0.0.0.0', port=8080)

index.html

<h3>Hi</h3>

index2.html

<h3>Bye</h3>

Running main.py returns:

Hi
Bye

Even though this makes sense, my goal is to make it result in just Bye which should replace Hi. I tried other paths like returning both but none of them worked. Any ideas on how I can do this?

programmerskillz
  • 168
  • 1
  • 12
  • I don't think you understand how a generator works... It needs to be called through either an iteration or via a `next`. – Error - Syntactical Remorse Apr 17 '19 at 22:51
  • @Error-SyntacticalRemorse Right, that's what I thought too, that the usage of a generator was incorrect in this situation but when I returned two files without a generator, only the first file's contents were visible. If you don't mind, can you show me what you mean when you say to utilize an iteration or the `next` function in this specific scenario. – programmerskillz Apr 17 '19 at 23:01

2 Answers2

6

It's not your case, but if you'd like to stream a template with static content, here's a way to do it. I'll be using the sleep() method to suspend the execution for 1 second.

from flask import Flask, stream_with_context, request, Response, flash
import time
from time import sleep

app = Flask(__name__)

def stream_template(template_name, **context):
    app.update_template_context(context)
    t = app.jinja_env.get_template(template_name)
    rv = t.stream(context)
    rv.disable_buffering()
    return rv

data = ['Hi', 'Bye']

def generate():
    for item in data:
        yield str(item)
        sleep(1)

@app.route('/')
def stream_view():
    rows = generate()
    return Response(stream_with_context(stream_template('index.html', rows=rows)))



if __name__ == "__main__":
    app.run()

where templates/index.html:

{% for item in rows %}
<h1>{{ item }}</h1>
{% endfor %}

See streaming from templates in the documentation.

Gabe
  • 956
  • 7
  • 8
1

You would have to do you function different to use a generator like this.

from flask import Flask, stream_with_context, Response, render_template
app = Flask('app')

def page_generator():
    yield render_template('index.html')
    yield render_template('index2.html')
generator_obj = None

@app.route('/')
def hello_world():
    global generator_obj
    generator_obj = generator_obj or page_generator()
    return Response(stream_with_context(next(generator_obj)))

app.run(host='0.0.0.0', port=8080)

I don't know for sure if this will work in flask. Note that after you call hello_world twice this will fail unless you reset generator_obj to None on StopIteration.