Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: return a StreamingHttpResponse on an existing html page

Since it is better to have a single question for each issue, be patient if is similar to another part of another my question related to the same project.

The situation:

I have a form on html in which I can set a number and when it is submitted, it is call views.stream_response which pass the value to stream.py and it returns a StreamingHttpResponse and "virtual" blank browser page appears (/stream_response/) in which I can see a progressive number every second up to m :

   1
   2
   3
   ..
   m

stream.py

import time

def streamx(m):
    lista = []
    x=0
    while len(lista) < m:      
        x = x + 1
        time.sleep(1)
        lista.append(x)
        yield "<div>%s</div>\n" % x 
        print(lista[-1])    
    return (x)

---UPDATE---

views.py

def stream_response(request):   
    test = InputNumeroForm()   
    if request.method == 'POST':
        test = InputNumeroForm(data=request.POST)
        if test.is_valid():
            m = test.cleaned_data['numero']     
            print (test)      
            print("m = ", m) 
            #resp = StreamingHttpResponse(stream_response_generator(m))
            resp = StreamingHttpResponse(stream.streamx(m))
            return resp               
        return render(request, 'homepage/provadata.html',{'user.username': request, 'test': test}, context_instance = RequestContext(request))

urls.py

...
url(r'^homepage/provadata/$', views.provadata),    
url(r'^stream_response/$', views.stream_response, name='stream_response'),
...

homepage/provadata.html

<form  id="numero" action="/stream_response_bis/" method="POST">
    {% csrf_token %}
    {{test}}                                
    <input type="submit" value="to view" />
</form> 

//{{ris}} 

I tried to do a render_to response to stay on homepage/provadata.html and to see the progressive lists but stream.py does not starts and I can see only the input number m on the command line.

I tried with THIS suggestion in views.py

def stream_response_generator(m):    
    ris = stream.streamx(m) 
    yield loader.get_template('homepage/provadata.html').render(Context({'ris': ris}))

(adding {{ris}} to template and
resp = StreamingHttpResponse(stream_response_generator(m)) in stream_response function) but I obtain on the template:

<generator object streamx at 0x0000000004BEB870>

And on command line it prints the input value but it not pass anymore the parameter to stream.py.

So.. How can I solve this issue?

like image 611
Trix Avatar asked Apr 30 '15 10:04

Trix


1 Answers

You can use the StreamingHttpResponse to indicate that you want to stream results back and all the middleware that ships with django is aware of this and acts accordingly to not buffer your content output but send it straight down the line.

You can disable the ETAG middleware using the condition decorator. That will get your response to stream back over HTTP. You can confirm this with a command-line tool like curl. But it probably won't be enough to get your browser to show the response as it streams. To encourage the browser to show the response as it streams, you can push a bunch of whitespace down the pipe to force its buffers to fill. Example follows:

from django.views.decorators.http import condition

@condition(etag_func=None)
def stream_response(request):
    resp = HttpResponse( stream_response_generator(), mimetype='text/html')
    return resp

def stream_response_generator():
    yield "<html><body>\n"
    for x in range(1,11):
        yield "<div>%s</div>\n" % x
        yield " " * 1024  # Encourage browser to render incrementally
        time.sleep(1)
    yield "</body></html>\n"
like image 102
sottany Avatar answered Nov 10 '22 01:11

sottany