webapp2 jinja2 context_processor - google-app-engine

I am building a project on GAE, webapp2, jinja2 and I use engineauth for authorization. I need something like Django's context_processor in order to use session, user and some other variables from webapp2.request in templates. Please, help me to solve this problem.

There are many ways to achieve this.
The simplest way probably looks like this:
def extra_context(handler, context=None):
"""
Adds extra context.
"""
context = context or {}
# You can load and run various template processors from settings like Django does.
# I don't do this in my projects because I'm not building yet another framework
# so I like to keep it simple:
return dict({'request': handler.request}, **context)
# --- somewhere in response handler ---
def get(self):
my_context = {}
template = get_template_somehow()
self.response.out.write(template.render(**extra_context(self, my_context))
I like when my variables are in template globals, then I can access them in my template widgets without having to pass around bunch of vars in template. So I am doing it like this:
def get_template_globals(handler):
return {
'request': handler.request,
'settings': <...>
}
class MyHandlerBase(webapp.RequestHandler):
def render(self, context=None):
context = context or {}
globals_ = get_template_globals(self)
template = jinja_env.get_template(template_name, globals=globals_)
self.response.out.write(template.render(**context))
There are other methods in: Context processor using Werkzeug and Jinja2

Related

How to access app's routes inside app engine cron job?

So I have the routes defined for my app inside main.py, something like:
app = webapp2.WSGIApplication([
webapp2.Route('/', handler=HomePage, name="home")
])
Inside the cron job I can't seem to access the routes of the app, for example this doesn't work:
self.uri_for('home')
I found somewhere online a snippet that fixes it, but it's ugly to use:
cls.app.router.add(r)
Where r would be an array of routes.
Is there a way to have acces to the app's routes inside an app engine cron job?
Your example is incorrect, it seems to be a cross between simple routes and extended routes.
To be able to use self.uri_for('home') you need to use named routes, i.e. extended routes:
app = webapp2.WSGIApplication([
webapp2.Route(r'/', handler=HomePage, name='home'),
])
With that in place self.uri_for('home') should work, assuming self is a webapp2.RequestHandler instance.
The workaround just looks ugly, but that is pretty much what uri_for does under the hood as well:
def uri_for(self, _name, *args, **kwargs):
"""Returns a URI for a named :class:`Route`.
.. seealso:: :meth:`Router.build`.
"""
return self.app.router.build(self.request, _name, args, kwargs)

Gae, webapp2 url with multiple parameters

I am currently work on a web app using webapp2, that deals with restaurant in several cities. Some of the url would look like
1. www.example.com/newyork
2. www.example.com/newyork/fastfood
3. www.example.com/newyork/fastfood/tacobell
To handle the first url, I used the following
CITY_RE = r'(/(?:[a-zA-Z0-9]+/?)*)'
app = webapp2.WSGIApplication([(CITY_RE, CityHandler)], debug = True)
How would I handle the url with multiple parameters such as 2 and 3.
I have a similar approach to match urls like /<country>/<region>/<city>/<category>e.g. /usa/california/losangeles/restaurants where I use this regex:
app = webapp2.WSGIApplication([('/([^/]+)/?([^/]*)/?([^/]*)', RegionSearch)], config=settings.w2config, debug=True)
The declare the relevant parameters in the handler class.
class RegionSearch(SearchBaseHandler):
"""Handles regional search requests."""
def get(
self,
region=None,
city=None,
category=None,
subcategory='For sale',
PAGESIZE=50, # items on page
limit=60, # number of days
year=2012,
month=1,
day=1,
next_page=None,
):
I think that you could even do it this way
webapp2.Route('/passwdresetcomplete/<city>/<category>/<name>', handler=RegionSearch, name='regionsearch')

How to call an instance of webapp.RequestHandler class inside other module?

I am trying to create a simple web application using Google App Engine. I use jinja2 to render a frontend html file. User enters their AWS credentials and gets the output of regions and connected with them virtual machines.
I have a controller file, to which I import a model file and it looks like this:
import webapp2
import jinja2
import os
import model
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
def request_a(self):
a = self.reguest.get('a')
return a
def request_b(self):
b = self.reguest.get('b')
return b
class Responce(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.write(testing_ec2.me.get_machines())
app = webapp2.WSGIApplication([('/2', MainPage), ('/responce', Responce)], debug=True)
then I have a model file, to which I import controller file and it looks like this:
import boto.ec2
import controller
import sys
if not boto.config.has_section('Boto'):
boto.config.add_section('Boto')
boto.config.set('Boto', 'https_validate_certificates', 'False')
a = controller.MainPage.get()
b = controller.MainPage.get()
class VM(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.regions = boto.ec2.regions(aws_access_key_id = a, aws_secret_access_key = b)
def get_machines(self):
self.region_to_instance = {}#dictionary, which matches regions and instances for this region
for region in self.regions:
conn = region.connect(aws_access_key_id = self.a, aws_secret_access_key = self.b)
reservations = conn.get_all_instances()#get reservations(need understand them better)
if len(reservations) > 0:#if there are reservations in this region
self.instances = [i for r in reservations for i in r.instances]#creates a list of instances for that region
self.region_to_instance[region.name] = self.instances
return self.region_to_instance
me = VM(a, b)
me.get_machines()
When I run this, it throws an error: type object 'MainPage' has no attribute 'request_a'
I assume, that it happens, because I do not call an instance of MainPage class and instead call a class itself. What is an instance of MainPage(and it`s parent webapp.RequestHandler) class? How do I call it inside another module?
Your code looks very strange to me. I do not understand your coding practice.
The general answer is : if you like to use methods of your MainPage, you can use inheritance.
But. If I understand the goal of your code. Why not call boto from your Responce class. But, here you use a get, where you should use a post, because you post a form with AWS credentials.
So I suggest :
create a MainPage with get and post methods to handle the form
in the the post method make the boto requests and send the result with jinja to the user.
See also Getting started with GAE Python27 and handling forms:
https://developers.google.com/appengine/docs/python/gettingstartedpython27/handlingforms?hl=nl

webapp2.Route with optional leading part

I am learning the webapp2 framework with its powerful Route mechanism.
My application is supposed to accept URIs like these:
/poll/abc-123
/poll/abc-123/
/poll/abc-123/vote/ # post new vote
/poll/abc-123/vote/456 # view/update a vote
Polls may optionally be organized into categories, so all the above should work also like this:
/mycategory/poll/abc-123
/mycategory/poll/abc-123/
/mycategory/poll/abc-123/vote/
/mycategory/poll/abc-123/vote/456
My incorrect configuration:
app = webapp2.WSGIApplication([
webapp2.Route('/<category>/poll/<poll_id><:/?>', PollHandler),
webapp2.Route('/<category>/poll/<poll_id>/vote/<vote_id>', VoteHandler),
], debug=True)
Question: How could I fix my configuration?
If possible it should be optimized for GAE CPU-time/hosting fee. For example, it may be faster if I add two lines for each entry: one line with category and another one without category...
webapp2 has a mechanism to reuse common prefixes, but in this case they vary, so you can't avoid duplicating those routes, as in:
app = webapp2.WSGIApplication([
webapp2.Route('/poll/<poll_id><:/?>', PollHandler),
webapp2.Route('/poll/<poll_id>/vote/<vote_id>', VoteHandler),
webapp2.Route('/<category>/poll/<poll_id><:/?>', PollHandler),
webapp2.Route('/<category>/poll/<poll_id>/vote/<vote_id>', VoteHandler),
], debug=True)
You should not worry about adding many routes. They are really cheap to build and match. Unless you have tens of thousands, reducing the number of routes won't matter.
A small note: the first route accepts an optional end slash. You could instead use the RedirectRoute to accept only one and redirect if the other is accessed, using the option strict_slash=True. This is not well documented but has been around for a while. See the explanation in the docstring.
I am going to add my solution to this as a complimentary answer on top of #moraes.
So other people having problems like below can get a more complete answer.
Trailing Slash Problem
Optional Parameter Problem
In addition, I figured out how to route both /entity/create and /entity/edit/{id} in one regex.
Below are my routes that supports the following url patterns.
/
/myentities
/myentities/
/myentities/create
/myentities/create/
/myentities/edit/{entity_id}
SITE_URLS = [
webapp2.Route(r'/', handler=HomePageHandler, name='route-home'),
webapp2.Route(r'/myentities/<:(create/?)|edit/><entity_id:(\d*)>',
handler=MyEntityHandler,
name='route-entity-create-or-edit'),
webapp2.SimpleRoute(r'/myentities/?',
handler=MyEntityListHandler,
name='route-entity-list'),
]
app = webapp2.WSGIApplication(SITE_URLS, debug=True)
Below is my BaseHandler that all my handlers inherit from.
class BaseHandler(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
# Sets the defaulte templates folder to the './app/templates' instead of 'templates'
jinja2.default_config['template_path'] = s.path.join(
os.path.dirname(__file__),
'app',
'templates'
)
# Returns a Jinja2 renderer cached in the app registry.
return jinja2.get_jinja2(app=self.app)
def render_response(self, _template, **context):
# Renders a template and writes the result to the response.
rv = self.jinja2.render_template(_template, **context)
self.response.write(rv)
Below is my MyEntityHandler python class with the get() method signature for the Google App Engine Datastore API.
class MyEntityHandler(BaseHandler):
def get(self, entity_id, **kwargs):
if entity_id:
entity = MyEntity.get_by_id(int(entity_id))
template_values = {
'field1': entity.field1,
'field2': entity.field2
}
else:
template_values = {
'field1': '',
'field2': ''
}
self.render_response('my_entity_create_edit_view_.html', **template_values)
def post(self, entity_id, **kwargs):
# Code to save to datastore. I am lazy to write this code.
self.redirect('/myentities')

Google App Engine logout url

I am having problems getting the logout link work in GAE (Python).
This is the page I am looking at.
In my template, I create a link
<p>Logout</p>
But when I click on it I get "broken link" message from Chrome. The url for the link looks like this:
http://localhost:8085/users.create_logout_url(
My questions:
Can anybody explain how this works in general?
What is the correct url for the dev server?
What is the correct url for the app server?
What is the ("/") in the logout url?
Thanks.
EDIT
This link works; but I don't know why:
<p>Logout</p>
What sort of templates are you using? It's clear from the output that you're not escaping your code correctly.
Seems to me that you want to do this instead:
self.response.out.write("This is the url: %s", users.create_logout_url("/"))
You could also pass it to your template, using GAEs implemented django templates.
from google.appengine.ext.webapp import template
...
...
(inside your request handler)
class Empty: pass
data = Empty()
data.logout = users.create_logout_url("/")
self.response.out.write(template.render(my_tmpl, {'data': data})
A useful approach is to add all sorts of info to a BaseRequestHandler and then use this as base class for all of your other request handler classes.
from google.appengine.ext import webapp
...
class BaseRequestHandler(webapp.RequestHandler):
def __init__(self):
webapp.RequestHandler.__init__(self) # extend the base class
class Empty: pass
data = Empty()
data.foo = "bar"
Then your new classes will have access to all the data you provided in the base class.
class OtherHandler(BaseRequestHandler):
def get(self):
self.response.out.write("This is foo: %s" % self.data.foo) # passes str "bar"
Hope it helps.
A.
Hi following more or less what this article is showing for the user account stuff. In gwt I store server side the logout/login url and I pass them to the client
http://www.dev-articles.com/article/App-Engine-User-Services-in-JSP-3002

Resources