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',)
Related
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?
I am trying to test my app but not sure how to configure the django-allauth in the test environment. I am getting:
ImproperlyConfigured: No Facebook app configured: please add a SocialApp using the Django admin
My approach so far is to instantiate app objects inside tests.py with actual Facebook app parameters, an app which functions correctly locally in the browser:
from allauth.socialaccount.models import SocialApp
apper = SocialApp.objects.create(provider=u'facebook',
name=u'fb1', client_id=u'7874132722290502',
secret=u'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
apper.sites.create(domain='localhost:8000', name='creyu.org')
How can I get these tests running? Thanks
Where inside tests.py do you instantiate this app object? If it's inside the setUpModule() method, there shouldn't be a problem.
Personally, I would create a fixture init_facebook_app.json with the relevant information and then inside tests.py (before the test cases) define:
from django.core.management import call_command
def setUpModule():
call_command('loaddata', 'init_facebook_app.json', verbosity=0)
This ensures that the data in the fixture are loaded before the tests are run, and that they are loaded only once, i.e. not before each test. See this for reference regarding call_command.
Lastly, posting your Facebook app secret key anywhere on the internet is not a good idea - I would reset it if I were you.
I would create a migration so all your environments have the data
eg
import os
from django.db import models, migrations
from django.core.management import call_command
from django.conf import settings
class Migration(migrations.Migration):
def add_initial_providers(apps, schema_editor):
import pdb;pdb.set_trace()
call_command(
'loaddata',
os.path.join(settings.BASE_DIR, 'fixtures/social_auth.json'),
verbosity=0)
dependencies = [
('my_app', '001_auto_20160128_1846'),
]
operations = [
migrations.RunPython(add_initial_providers),
]
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(...)
I am in the process of migrating some GAE apps from Python 2.5 to 2.7. It seems much more difficult to import Django templates (any version) into this version of Python. I followed Google's instructions to the T and scoured the web for help, but ultimately failed. So here is what I tried, and I was wondering if any of you guys would be able to help me! Thanks in advance.
In app.yaml:
libraries:
- name: django
version: "1.2"
In main.yaml:
import os
# specify the name of your settings module
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
import django.core.handlers.wsgi
app = django.core.handlers.wsgi.WSGIHandler()
The main class:
class Main(webapp2.RequestHandler):
def get(self):
self.response.out.write(template.render('index.html', None))
The Error I get:
NameError: global name 'template' is not defined
Interestingly, it worked with Jinja2 templates. However, all HTML code was written using Django templates and I think it would be too time consuming to convert them all. Here's the Jinja2 code that worked (all in one code block for simplicity).
libraries:
- name: jinja2
version: latest
import jinja2
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class Main(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
Your template is undefined; you'll need to import it from webapp:
from google.appengine.ext.webapp import template
webapp2 is backwards compatible with webapp but you'll need to use the template engine from webapp still, see Using templates.
Can anyone suggest a detailed resource for including django 1.2 templating in our GAE apps? So far I have found
docs describing how to zip up the django files and add them to our project
docs on running native django projects in GA
docs about including 1.0 and 1.1 libraries into our projects
but nothing yet describing how to use django 1.2 templates in our projects. Specifically, how to formulate the arcane wizardry at the top of my python script that will magically convince GAE to use my zipped up django library.
I have this in my python script:
import sys
sys.path.insert(0, 'django/django.zip')
And similar to the GAE tutorial, here's how I'm rendering the template:
template_values = {
'formerror': formerror,
'media': media,
'status': status
}
path = os.path.join(os.path.dirname(__file__), formtemplate)
self.response.out.write(template.render(path, template_values)
But there is some piece missing for GAE to use Django 1.2 to render the templates. What is it?
I used this:
from google.appengine.dist import use_library
use_library('django', '1.1')
from google.appengine.ext.webapp import template
In this case I used 1.1 version but I think it should work the same for 1.2.
I had the same problem a while ago - I wanted to use version 1.2 version for templates instead of 0.96 (that is provided by GAE). The following code seems to work for me.
# some standard Google App Engine imports (optional)
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext import db
# Remove Django modules (0.96) from namespace
for k in [k for k in sys.modules if k.startswith('django')]:
del sys.modules[k]
# Force sys.path to have our own directory first, in case we want to import
# from it. This way, when we import Django, the interpreter will first search
# for it in our directory.
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
# Must set this env var *before* importing any part of Django
# (that's required in Django documentation)
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
# New Django imports
from django.template.loader import render_to_string
from django.conf import settings
# Configure dir with templates
# our template dir is: /templates
TEMPLATE_DIR = os.path.join(os.path.dirname(__file__),'templates')
settings.configure(TEMPLATE_DIRS = (TEMPLATE_DIR,'') )
However, if you need only templates from Django, and no other API, consider using Jinja instead. That's what I'm planning to do.