Running webapp2 app in a multiple WSGI apps set up with Werkzeug - python

I am trying to run a django app and a webapp2 app together in one python interpreter. I'm using werkzeug for that as described here.
Here's my sample code.
from werkzeug.wsgi import DispatcherMiddleware
from django_app import application as djangoapp
from webapp2_app import application as webapp2app
application = DispatcherMiddleware(djangoapp, {
'/backend': webapp2app
})
After doing this, I would expect all requests to /backend should be treated by the webapp2 app as /. But it treats the requests as /backend. This work fines with other WSGI apps using django or flask. The problem only appears with webapp2 apps. Does anyone have any suggestions how to overcome this? Is there any other way I can achieve my purpose without using werkzeug for serving multiple WSGI apps under one domain?

DispatcherMiddleware fabricates environments for your apps and especially SCRIPT_NAME. Django can deal with it with configuration varibale FORCE_SCRIPT_NAME = '' (docs).
With Webapp2 it's slightly more complicated. You can create subclass of webapp2.WSGIApplication and override __call__() method and force SCRIPT_NAME to desired value. So in your webapp2_app.py it could be like this
import webapp2
class WSGIApp(webapp2.WSGIApplication):
def __call__(self, environ, start_response):
environ['SCRIPT_NAME'] = ''
return super(WSGIApp, self).__call__(environ, start_response)
# app = WSGIApp(...)

Related

Using Django to authenticate user from Flask

How would you access the Django authentication framework from a Flask app?
I have a Django app and Flask app running in parallel on a server. Both are hosted behind the same domain, but behind different paths, so they should be able to see each other's cookies.
I'm using Flask to run a simple API microservice, where using Django would be overkill. However, to prevent abuse, I still want Flask to check the request's cookies to see if they're from a user who's still authenticated in the Django application. I don't want to re-implement an authentication framework in Flask.
Access Django settings from inside Flask is relatively simple. I just put something like this at the top of my Flask script to set the path to my Django settings module:
sys.path.insert(0, <path to Django project>)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mydjangoproject.settings")
from django.conf import settings
However, I'm unsure how to update a Flask request handler to pull the correct cookies from a request and verify them with Django's authentication backend. How would I do this?
Digging through the Django interals for the session and authentication middleware, it looks like it's pretty easy to fed Flask's native request instance to them. This seems to do it for me:
from importlib import import_module
from django.conf import settings
from django.contrib.auth.middleware import get_user
engine = import_module(settings.SESSION_ENGINE)
SessionStore = engine.SessionStore
session_key = request.cookies.get(settings.SESSION_COOKIE_NAME)
request.session = SessionStore(session_key)
user = get_user(request)
print(user.is_authenticated)

How to share sessions between modules on a Google App Engine Python application with django framework?

Here is a similar question: How to share sessions between modules on a Google App Engine Python application?
I have two modules: default and helloworld
I want all the myapp.appspot.com/helloworld/* will be routed to the helloworld module.
The dispatch.yaml is as follows:
application: myapp
dispatch:
- url: "*/helloworld/*"
module: helloworld
when I request myapp.appspot.com/helloworld/, it will be redirected to the login page as I use the #require_login in helloworld.urls.
helloworld.urls:
from django.contrib.auth.decorators import login_required
urlpatterns = patterns('',
url(r'^$', login_required(views.home.as_view()), name='helloworld-home'),
)
However, the login_require is routed to /account/login and is processed by the default module, and the helloworld module can not share the session created by the default module.
Therefore, I will be redirected again to the login page after I login in.
Here is my wsgi.py
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'libs'))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
The possible solution with webapp2 will pass a config to the wsgi application:
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
cookie_args': {
'domain' : "yourapp.appspot.com"
}
But I can not find any doc related to django :(
Is it possible to share the session between modules when using django framework in GAE?

How to import the app using flask foundation?

I am using Flask foundation to begin with my new flask app.
The init.py file has a method:
def create_app(object_name, env="prod"):
"""
An flask application factory, as explained here:
http://flask.pocoo.org/docs/patterns/appfactories/
Arguments:
object_name: the python path of the config object,
e.g. sservice.settings.ProdConfig
env: The name of the current environment, e.g. prod or dev
"""
app = Flask(__name__)
app.config.from_object(object_name)
app.config['ENV'] = env
#init the cache
cache.init_app(app)
debug_toolbar.init_app(app)
#init SQLAlchemy
db.init_app(app)
login_manager.init_app(app)
# Import and register the different asset bundles
assets_env.init_app(app)
assets_loader = PythonAssetsLoader(assets)
for name, bundle in assets_loader.load_bundles().iteritems():
assets_env.register(name, bundle)
# register our blueprints
from controllers.main import main
app.register_blueprint(main)
return app
that is imported in manage.py.
But what If I need to use this app variable to access the application configuration in modules within the application? I can't use current_app outside request contexts. Creating one is ugly.
I need to have a app variable in my models.py file:
In models.py
# how to import? Below doesn't work
from appname import app
# access config
print(app.config)
I can't call this method create_app, because it should be only called once to create the application. Not anytime you need to import the app. How should I solve this?
I only want to use create_app() exactly once outside the package to give it the wsgi server, but I don't want to use it within the package.
What is working now for me:
Wherever there is no current_app (outside of request contexts I guess) just use something like this
app = Flask(__name__)
app.config.from_object('appname.settings_file.DevConfig')
print(app.config)

Inheriting configuration from parent app in Flask

I have an application that is constructed as follows:
app = Flask(__name__)
app.wsgi_app = DispatcherMiddleware(frontend.create_app(), {
'/api': api.create_app()
})
app.config['DATABASE'] = db
I want to access the same database in both the frontend and api apps, but when I run something like current_app.config['DATABASE'] in Blueprints registered to api, that raises KeyError: 'DATABASE'. Is it possible to inherit configurations so that tests, etc. need only modify the top-level abstraction? Thanks.
Simply change your create_app methods on frontend and api to take a configuration dictionary and use flask.Config to create a configuration with all the properties of app.config (loadable from environmental variables, etc.):
from flask import Config
from werkzeug.wsgi import DispatcherMiddlware
config = Config()
config.from_envvar("YOUR_PROGRAM_CONFIG")
app = DispatcherMiddlware(frontend.create_app(config), {
'/api': api.create_app(config)
})
Then you can merge the provided config with each of your app's configurations:
def create_app(config):
app = Flask(__name__)
app.config.update(config)
# Potentially, load another config
app.config.from_envvar("YOUR_PROGRAM_CONFIG_FRONTEND", silent=True)
return app
Note that there is no need to create an app to route to other apps - the dispatcher middleware can already do that for you.
Also note that if you are already using blueprints it may make more sense to simply ship the blueprints and compose them on a single application, rather than using dispatcher middleware (depending, of course on how complex your apps are).

Unit testing Django templates in Google App Engine raises TemplateDoesNotExist(name)

I am trying to set up unit testing of a series of Django templates in Google App Engine using the python unittest framework.
The app uses python 2.7, webapp2, Django 1.2, and is already using unittest for testing the none Django functionality. The Django templates have no issues serving through the server in dev and live environments.
When executing the page call through the unittest framework the following error is raised:
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/django_1_2/django/template/loader.py", line 138, in find_template
raise TemplateDoesNotExist(name)
TemplateDoesNotExist: site/index.html
Settings.py:
import os
PROJECT_ROOT = os.path.dirname(__file__)
TEMPLATE_DIRS = (
os.path.join(PROJECT_ROOT, "templates"),
)
Unit test call:
import webapp2
import unittest
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from google.appengine.dist import use_library
use_library('django', '1.2')
import main
class test_main(unittest.TestCase):
def test_default_page(self):
request = webapp2.Request.blank('/')
response = request.get_response(main.app)
self.assertEqual(response.status_int, 200)
I've found it necessary to specify DJANGO_SETTINGS_MODULE and the Django version within the test file even though these are normally specified through app.yaml
The page handler:
from django.template.loaders.filesystem import Loader
from django.template.loader import render_to_string
class default(webapp2.RequestHandler):
def get(self):
self.response.out.write(render_to_string('site/index.html'))
I've tried stripping everything out of index.html but still get the same error.
I've tried using an explicit path for TEMPLATE_DIRS but no change.
Any ideas?
Check if this is set anywhere in your django config:
TEMPLATE_LOADERS=('django.template.loaders.filesystem.load_template_source',)

Categories