Search code examples
flasksubdomain

Flask and SubdomainDispatcher, how the application is run at first?


I'm building a website using Flask, and I'd like to use the indicated SubdomainDispatcher, but I don't know how to make it work (it's missing the initial run to start the server).

Here's the code :

The create_app function given here :

def create_app(database_uri, debug=False):
    app = Flask(__name__)
    app.debug = debug

    # set up your database
    app.engine = create_engine(database_uri)

    # add your modules
    app.register_module(frontend)

    # other setup tasks

    return app

The SubdomainDispatcher :

class SubdomainDispatcher(object):

    def __init__(self, domain, create_app):
        self.domain = domain
        self.create_app = create_app
        self.lock = Lock()
        self.instances = {}

    def get_application(self, host):
        host = host.split(':')[0]
        assert host.endswith(self.domain), 'Configuration error'
        subdomain = host[:-len(self.domain)].rstrip('.')
        with self.lock:
            app = self.instances.get(subdomain)
            if app is None:
                app = self.create_app(subdomain)
                self.instances[subdomain] = app
            return app

    def __call__(self, environ, start_response):
        app = self.get_application(environ['HTTP_HOST'])
        return app(environ, start_response)

The main app :

def make_app(subdomain):
    user = get_user_for_subdomain(subdomain)
    if user is None:
        # if there is no user for that subdomain we still have
        # to return a WSGI application that handles that request.
        # We can then just return the NotFound() exception as
        # application which will render a default 404 page.
        # You might also redirect the user to the main page then
        return NotFound()

    # otherwise create the application for the specific user
    return create_app(user)

application = SubdomainDispatcher('example.com', make_app)

So far, my code works without errors, but then, it stops. This is normal because no where, there is the :

if __name__ == "__main__":
    application = create_app(config.DATABASE_URI, debug=True)
    application.run()

code that make the initial server to be run.

I tried this :

if __name__ == "__main__":
    application = SubdomainDispatcher('example.com', make_app)
    application.run()

But it fails with :

AttributeError: 'SubdomainDispatcher' object has no attribute 'run'

How can I run it using the SubdomainDispatcher ?


Solution

  • Let's analyze your code.

    You create a SubdomainDispatcher class that creates a Flask application and return it based on the host passed in get_application

    This is also a callable.

    The problem is that the .run method is of the Flask object (the application itself). It is used to only test the application during development and it works for the single application.

    So you can't test it with the development server as a whole system. You can test only one of the domains (app) at a time.

    if __name__ == "__main__":
        application = SubdomainDispatcher('example.com', make_app)
        app = application.get_application('example.com')
        app.run()
    

    The test server is not a full featured server.

    Better Solution

    BTW I think that if you explain what you're trying to achieve (and not how you plan to do it in flask :) ) we could find a better solution. i.e. using the Flask subdomain keyword, or using a @before_request that localize the app parameters based on something. If the problem is only loading a user class based on the subdomain, there's no need of different Flask Apps (in particural cause you're using the same codebase) but you only need one @before_request handler.