﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
2904	Twisted support for Django with Defer enable	cenyongh@…	Adrian Holovaty	"In #172,jnoetzelman@gmail.com has submited a method to make Django run on top of twisted.He use twsited WSGIResource to wrap the django'WSGIHandler.But this method can not support Defer. The whole structure of this method is similiar to this diagram:
{{{         
    (Twisted)                 (Django)
    WSGIResource
         |
        \/
    WSGIHandler     -->      WSGIHandler
}}}

When http request come in WSGIResource will create a new Twisted WSGIHandler then this new created Handler will ask Django's WSGIHandler to process the request,after the response send back by django's handler,twisted handler will write it back to the client.

But if the django's handler send back a defer,the whole train will break.

My method has to subclass all the class in the diagram

{{{
#!python
class WrapDjangoWSGIHandler( BaseHandler ):
    def __call__( self, environ, start_response ):
        from django.conf import settings

        if settings.ENABLE_PSYCO:
            import psyco
            psyco.profile()

        # Set up middleware if needed. We couldn't do this earlier,because settings weren't available.
        if self._request_middleware is None:
            self.load_middleware ()

        dispatcher.send( signal=signals.request_started )
        try:
            request = WSGIRequest( environ )

            #   modified by cenyongh to support defer
            di = defer.maybeDeferred( self.get_response, request.path,request )
            def cb( response ):
                return self.done( response, start_response )
            di.addCallback( cb )
        finally:
            dispatcher.send( signal=signals.request_finished )

        return di;

    def done( self, response, start_response ):
        # Apply response middleware
        for middleware_method in self._response_middleware:
            response = middleware_method( request, response )
        try:
            status_text = STATUS_CODE_TEXT[ response.status_code]
        except KeyError:
            status_text = 'UNKNOWN STATUS CODE'
        status = '%s %s' % ( response.status_code, status_text )
        response_headers = response.headers.items ()
        for c in response.cookies.values():
            response_headers.append( ( 'Set-Cookie', c.output(header='' ) ) )
        start_response( status, response_headers )
        return response

class WrapTW2WSGIResource( wsgi.WSGIResource ):
    def renderHTTP( self, req ):
        from twisted.internet import reactor
        # Do stuff with WSGIHandler.

        #   modified by cenyongh to support defer
        handler = WrapTW2WSGIHandler( self.application, req )

        # Get deferred
        d = handler.responseDeferred
        # Run it in a thread
        reactor.callInThread( handler.run )
        return d

class WrapTW2WSGIHandler( wsgi.WSGIHandler ):
    def run( self ):
        from twisted.internet import reactor
        # Called in application thread
        try:
            result = self.application ( self.environment,self.startWSGIResponse )

            #   modified by cenyongh to support defer
            def cb( response ):
                self.handleResult( [response.content] )
            result.addCallback( cb )

        except Exception, e:
            if not self.headersSent:
                reactor.callFromThread( self.__error, failure.Failure())
            else:
                reactor.callFromThread( self.stream.finish,failure.Failure() )
}}}

----

Then the server could be construt as #172 did.But the follow lines 
{{{
#!python
test = wsgi.WSGIResource(AdminMediaHandler(WSGIHandler()))
site = server.Site(res)
}}}
should be change to
{{{
#!python
test = WrapTW2WSGIResource( WrapDjangoWSGIHandler() )
site = server.Site( test )
}}}

----
I have test with the views.py like this? And it get work.
{{{
#!python
def index( request ):
    return render_to_response( 'world/index.html', {} )


def dindex( request ):
    def cb( raw_html ):
        return render_to_response( 'world/index.html', {} )

    d = client.getPage( ""http://www.gmail.com"" )
    d.addCallback( cb )
    return d
}}}"	enhancement	closed	Tools	dev	normal	wontfix	Twisted Defer		Unreviewed	0	0	0	0	0	0
