This is my app.yaml:
- url: /about|/about/.*
script: about.py
This is my `about.py':
application = webapp.WSGIApplication([(r'^/about$', AboutPage),
(r'^/about/$', Redirect),
(r'.*', ErrorPage)],
debug = True)
I want to redirect all requests for /about/ to /about. I'd like all other requests to be sent to the error page.
It works in the development server on localhost, but I cannot access /about/ after I deployed the app on GAE - it just shows an empty page.
I adjusted the order of URL patterns in app.yaml.
It works now on GAE.
If you don't want trailing slashes for GET requests anywhere in your application, you can implement a global redirect at the top of your app.yaml. Note that POST requests will NOT redirect, but this is ok (for me anyway) because users don't generally hand-write POST URLs.
app.yaml:
application: whatever
version: 1
api_version: 1
runtime: python
handlers:
- url: .+/
script: slashmurderer.py
slashmurderer.py
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class SlashMurdererApp(webapp.RequestHandler):
def get(self, url):
self.redirect(url)
application = webapp.WSGIApplication(
[('(.*)/$', SlashMurdererApp)]
)
def main():
run_wsgi_app(application)
I see that this question has already been answered, but I ran into the same problem and wanted to see if there was a "lazier" solution.
If you're using the Python 2.7 runtime, then the webapp2 library is available, and I believe the following will work:
import webapp2
from webapp2_extras.routes import Redirect Route
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write("This is my first StackOverflow post")
app = webapp2.WSGIApplication([
RedirectRoute('/', MainHandler, name='main', strict_slash=True),
('/someurl', OtherHandler),
])
strict_slash=True means that if the client doesn't supply the slash it will be redirected to the url with the slash (to match the first argument).
You can combine the special Route classes from webapp2_extras with normal (regex, handler) tuples as shown above. The "name" parameter is required for the constructor for RedirectRoute. More details here: webapp2_extras documentation for RedirectRoute
Related
I am in a situation where I have one app engine service (service-a) that needs to handle a particular path (domain.com/some/particular/path) and I have another app engine service on the same domain (service-b) that needs to handle all other traffic to that domain (domain.com/*).
I've tried structuring my dispatch.yaml as follows, however no matter what I do the domain.com/some/particular/path ends up getting handled by service-b rather than service-a. In other words, all paths are being routed to service-b.
dispatch:
- url: "domain.com/some/particular/path"
service: service-a
- url: "domain.com/*"
service: service-b
How can I handle this situation?
This seems to be more about your code than the dispatch.yaml file that is roting to service-b. For example, I deployed two services, service 1:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Service 1'
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
And service 2:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Service 2'
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
With the following dispatch.yaml:
dispatch:
- url: "domain.com/app2/"
service: app2
- url: "domain.com/*"
service: default
If I try to access to domain.com/app2/ it shows NOT FOUND error message. If I change the routing in service 2 from #app.route('/') to #app.route('/app2') it works like a charm.
I think that your dispatch.yaml redirects to your service-a but the code inside that service redirects to domain.com.
BTW, if inside your services all your .yaml files are named app.yaml GAE for an unknown reason redirect to the default service so it's better to name every .yaml as the service it handles.
I am new to Flask and I am trying to organize my code as a large application for deployment on Google App Engine. I am using Flask-Classy to help organize my application into logical packages.
The application runs on the dev server just fine with one exception. When I set login: required or login: admin in my app.yaml (see app.yaml below), the application appears to skip over the mock Google Login page and automatically signs in as 'test#example.com'.
Normally, I would expect to see the standard Google mock authentication form (below) when login:required or login: admin is set in the app.yaml. However, when I point the browser to the '/' or any other uri, I am directed right to the respective page without authenticating via this form.
I am not sure what I am missing/doing wrong. I am not getting any type of errors.
Below, I have included my application's structure and most of the pertinent code to see if anyone might be able to point out anything I am doing wrong here.
/flask_app
/flask_app
/mod_one
/__init__.py
/forms.py
/views.py
/models.py
/mod_two
/__init__.py
/forms.py
/views.py
/models.py
/static
/css
...
/templates
/index.html
...
/__init__.py
/settings.py
/urls.py
/lib
/app.yaml
/appengine_config.py
/main.py
app.yaml
application: flask-app
version: 1
runtime: python27
api_version: 1
threadsafe: yes
default_expiration: "30d"
builtins:
- deferred: on
- admin_redirect: on
handlers:
- url: /css
static_dir: flask_app/static/css
- url: /admin/.*
script: main.app
login: admin
- url: /.*
script: main.app
login: required
appengine_config.py
import sys
import os.path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib'))
main.py
from flask_app import app
app = app
flask_app/init.py
import os
from flask import Flask
from flask_bootstrap import Bootstrap
from werkzeug.debug import DebuggedApplication
app = Flask(__name__)
if os.getenv('FLASK_CONF') == 'TEST':
app.config.from_object('flask_app.settings.Testing')
elif 'SERVER_SOFTWARE' in os.environ and os.environ['SERVER_SOFTWARE'].startswith('Dev'):
# Development settings
app.config.from_object('flask_app.settings.Development')
app.wsgi_app = DebuggedApplication(app.wsgi_app, evalex=True)
else:
app.config.from_object('flask_app.settings.Production')
# Instantiate Flask-Bootstrap.
Bootstrap(app)
import urls
flask_app/urls.py
from flask import render_template
from flask_app import app
#app.route('/')
def index():
params = {
'page_title': 'Home'
}
return render_template('index.html', **params)
#app.route('/contact')
def contact():
params = {
'page_title': 'Contact'
}
return render_template('contact.html', **params)
#app.route('/about')
def about():
params = {
'page_title': 'About'
}
return render_template('about.html', **params)
# Error handlers
# Handle 404 errors
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
# Handle 500 errors
#app.errorhandler(500)
def server_error(e):
return render_template('500.html'), 500
# Register Flask Classy Classes
import mod_one.views as mod_one
import mod_two.views as mod_two
mod_one.OneView.register(app)
mod_two.TwoView.register(app)
As #Greg pointed out in a comment to the question, I was already 'logged in' to the dev_appserver (which threw me off since I never saw the mock login page) so authentication was happening using the default 'test#example.com' user.
Once I went to /_ah/login I was able to access the mock login page and proceed as usual from there.
I use the following code to use webapp2
import webapp2
from webapp2_extras import i18n, jinja2
class Test(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
# Returns a Jinja2 renderer cached in the app registry.
return jinja2.get_jinja2(app=self.app)
def render(self, _template, **context):
# Renders a template and writes the result to the response.
rv = self.jinja2.render_template(_template, **context)
self.response.write(rv)
def get(self):
self.render('index2.html')
app = webapp2.WSGIApplication([('/',Test)], debug=False)
app.run()
To be simple, we just make index2.html is full of 1000 test
If you run it, you will find that the Google App Engine Launcher log windows is full of test.
It's rather terrible when you are debugging a real website.
But I find that if index2.html contains just few words like 10 test. The test will not appear in logging window.
Any solution?
It looks like you are running two separate instances of your application.
The first is running through the development server, the second is actually running and outputting to the terminal. You can see this by adding a log output to your application. You can see that when you go to your site, the log is written two twice.
You can fix this by removing the line:
app.run()
This is not necessary when running on App Engine. Your app.yaml file references the app directly:
handlers:
- url: .*
script: guestbook.app # Notice the .app here.
can anyone tell me please the difference between these two code snippets:
1.
import webapp2
from google.appengine.api import users
class MainPage(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, ' + user.nickname())
else:
self.redirect(users.create_login_url(self.request.uri))
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
2.
import webapp2
from google.appengine.api import users
class MainPage(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, ' + user.nickname())
else:
self.redirect(users.create_login_url(self.request.uri))
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
The thing is that i'm trying to go over Google AppEngine introduction material and whenever i try to type the code myself, something's different and it doesn't work. And whenever i just copy it from their website, it works, although it looks identical.
Checked the coding in the View panel, it's same, ANSI (i'm using Notepad++).
Tried to play with indentation as well and it didn't made any difference.
Any comments would be appreciated.
Thank you.
You should always start your Pyhton code with these 3 lines:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
And your editor should encode in utf-8. Do not use ANSI.
The last line is optional, but I recommend it, to stay away from encoding problems. There are a few exceptions. So if you use unicode literals, you have to change the line with the headers:
import webapp2
from google.appengine.api import users
class MainPage(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
self.response.headers['Content-Type'.encode()] = 'text/plain'.encode()
self.response.out.write('Hello, ' + user.nickname())
else:
self.redirect(users.create_login_url(self.request.uri))
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
And your app.yaml should look like:
application: helloworld
version: 1
runtime: python27
api_version: 1
threadsafe: false
handlers:
- url: /.*
script: helloworld.app
libraries:
- name: webapp2
version: latest
But Notepad++ is not a good development environment for app engine. You need a good Python IDE. I recommend Eclipse with PyDev. To setup, use this totorial see this question: Debug google app engine project line by line
And if you are a total newbie? go to this great web development course using google app engine : http://www.udacity.com/overview/Course/cs253/CourseRev/apr2012
Found a problem, it was indentation thing.
You can read about this here and here
There's difference whether you are using "space" or "tab" to indent and it can cause problems,
also problems can occur from settings in your program (in my case in Sublime Text's setting of "Tab" indent,it can be set to 4 or 8 etc.)
I want to have multiple pages in google-app engine (python 2.7) and the followoing is my directory structure:
root contains: pujaweb.py (the main script), index.html, stylesheets(folder), port(folder)...
now my second script for the page is in the port folder and i want to configure my index.html such that it links to that page. I have tried a lot of stuff but somehow it does not work and always shows 404 page not found error and the command line says that PujaPort module does not exist (pujaport being the app handler for the second page).
the following is my app.yaml file code:
application: thepujabhalerao
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /images
static_dir: images
- url: /stylesheets
static_dir: stylesheets
- url: /port
script: pujaport.app
- url: /.*
script: pujaweb.app
libraries:
- name: jinja2
version: latest
this is my main handler (pujaweb.py)
import cgi
import webapp2
import jinja2
import os
from google.appengine.api import xmpp
from google.appengine.ext import db
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class MainPage(webapp2.RequestHandler):
def get(self):
template_values = {}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
and the href in the index filer looks like this:
P
and finally this is the second page handler pujaport.py:
import cgi
import webapp2
import jinja2
import os
from google.appengine.api import xmpp
from google.appengine.ext import db
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class PujaPort(webapp2.RequestHandler):
def get(self):
self.response.out.write("In handler")
app = webapp2.WSGIApplication([('/port', PujaPort)],
debug=True)
I know its a minor glitch somewhere but please help me out as after being on it for too long i maybe missing the obvious.
If you insist on using that folder structure, you'll need to make the port directory into a package by adding an __init__.py file to it (which can be empty), and reference the app as port.pujaport.app, its fully qualified name.