9

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?

Community
  • 1
  • 1
Trix
  • 587
  • 1
  • 6
  • 27
  • did you look at this answer: http://stackoverflow.com/questions/2922874/how-to-stream-an-httpresponse-with-django – ger.s.brett Apr 30 '15 at 15:19
  • @ger.s.brett Yes, but it points (like in my case) into a "not physically existing" html page... I don't know how explain this in a clearer way. – Trix Apr 30 '15 at 15:24
  • if you want to use ajax - why do you need the stream at all? – ger.s.brett May 01 '15 at 07:34
  • In many answers or comments I saw that people refer to ajax... so I tried with it but I think that for my purpose StreamHttpResponse is the solution. I'am new in programming and probably there are many things that I don't know, so I asked here for some help. – Trix May 04 '15 at 08:00
  • Have you solved you question ? Do you need a proper answer ? – Charlesthk May 16 '15 at 15:38
  • No, I did not solved yet. – Trix May 18 '15 at 07:25
  • stream.py is not correct - there is syntax error (you can't have return with value in generator). So it seems that you did not publish question correctly. – Konstantin Svintsov Sep 14 '15 at 10:48

1 Answers1

3

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"
sottany
  • 1,098
  • 8
  • 14