I want to show my fancy 404 page in pyramid app, but can get it working. After reading various magic texts about the subject, I put something like this in my code:
cfg.add_view( "Page_not_found_view", renderer="page_404.mak",
context=HTTPNotFound )
But while my *Page_not_found_view* handler is invoked (I can see its' trace) I still get that poor "default" 404 page instead of *my own page_404.mak*. Any ideas?
Here's an example app that uses an exception view to catch the pyramid.httpexceptions.HTTPNotFound view raised by Pyramid when no view can be found that matches:
from waitress import serve
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
return Response('<html><body>Hello world!</body></html>')
def notfound(request):
return Response('<html><body>Not found!</body></html>')
if __name__ == '__main__':
config = Configurator()
config.add_view(hello_world)
config.add_view(notfound, context='pyramid.httpexceptions.HTTPNotFound')
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
Visiting '/' will return "Hello world!", visiting "/abc" or "/def" (or anything else that isn't found) will return "Not found!".
What #chris-mcdonough wrote should work in most cases. However, if you are using a matchdict in your view callable and want to show your custom 404 page when nothing matches, make sure that you raise the HTTPNotFound exception instead of returning it. Otherwise, you will get the default 404 page.
Example:
from pyramid import httpexceptions
def my_page(self):
id = self.request.matchdict.get('id', None)
if not id:
raise httpexceptions.HTTPNotFound()
else:
# do whatever here
Related
I have a handler that wraps a function and does some logging and a few other things, almost like middleware. I want to wrap that around flask's default 404, 500 replies. How would this be done? For example:
#app.errorhandler(404)
#my_handler
def error404(*args, **kwargs):
return "404 - page not found", 404
# how to instead return the existing flask 404 call/page?
Basically, I just want to execute the error404 function but pass a handler around it. What should I return then?
Inspiring this example I tried this and it seems to work in the way you need.
#app.errorhandler(404)
#my_handler
def error404(e):
return e.get_response()
I am studying this course on flask. This is the basic flask code. When I am on the first route I am fine but when I try to put slash and got for another page it doesn't work.
I get this message:
"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."
I did run FLASK_APP=app.py flask run
after saving.
from Flask import flask
app= Flask(__name__)
#app.route('/')
def index():
return "index"
#app.route('/me')
def me():
return "me"
if __name__== "__main__":
app.run(debug=True)
In class it works well. When i do it it does not
127.0.0.1 - - [08/Jul/2019 02:43:55] "GET /me/ HTTP/1.1" 404 -
I'm guessing 404 at the end is problem
After the reply
from Flask import flask
app= Flask(__name__)
strict_slashes=False
#app.route('/')
def index():
return "index"
#app.route('/me/')
def me():
return "me"
if __name__== "__main__":
app.run(debug=True)
You have declared your "/me" route explicitly without trailing slash. However, when calling the URL, you are calling it with slash in the end "/me/". Werkzeug (Flask development application server) by default has the rule of "strict_slashes=True", which requires you to follow exact route declaration when calling your URLs. In other words, if in your code, you declared "#app.route('/me'), your should call "127.0.0.1/me", not "127.0.0.1/me/".
Removing the slash in the end (e.g. http://localhost/me) will fix your issue. You can also change the Werkzeug setting and set strict_slashes=False if you want to remove the default rule.
I would say make a app.errorhandler(404) and then define what to do after you get an error to check if it is a 404 error, and other errors. I would also say use html and make links which you can use to go into different pages, it is easier than typing manually. here is my code:
python:
from flask import Flask, render_template
app = Flask(__name__)
app.route('/')
def home():
return render_template('home.html')
app.route('/me')
def me():
return 'me'
app.errorhandler(404)
def error(arg):
return 'wrong url'
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
html:
<!-- you can use css to make the link look better or <style> </style>-->
I am trying to alter the Pyramid hello world example so that any request to the Pyramid server serves the same page. i.e. all routes point to the same view. This is what iv got so far:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
return Response('Hello %(name)s!' % request.matchdict)
if __name__ == '__main__':
config = Configurator()
config.add_route('hello', '/*')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
All iv done is change the line (from the hello world example):
config.add_route('hello', '/hello/{name}')
To:
config.add_route('hello', '/*')
So I want the route to be a 'catch-all'. Iv tried various variations and cant get it to work. Does anyone have any ideas?
Thanks in advance
The syntax for the catchall route (which is called "traversal subpath" in Pyramid) is *subpath instead of *. There's also *traverse which is used in hybrid routing which combines route dispatch and traversal. You can read about it here: Using *subpath in a Route Pattern
In your view function you'll then be able to access the subpath via request.subpath, which is a tuple of path segments caught by the catchall route. So, your application would look like this:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
if request.subpath:
name = request.subpath[0]
else:
name = 'Incognito'
return Response('Hello %s!' % name)
if __name__ == '__main__':
with Configurator() as config:
config.add_route('hello', '/*subpath')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8081, app)
server.serve_forever()
Don't do it via custom 404 handler, it smells of PHP :)
You could create a custom error handler (don't remember off the top of my head but it was in the Pyramid docs) and capture HTTP 404 errors, and redirect/render your catch-all route from there.
The link I'm thinking of: http://docs.pylonsproject.org/projects/pyramid//en/latest/narr/hooks.html
I've done something like this:
from pyramid.view import (
view_config,
forbidden_view_config,
notfound_view_config
)
from pyramid.httpexceptions import (
HTTPFound,
HTTPNotFound,
HTTPForbidden,
HTTPBadRequest,
HTTPInternalServerError
)
import transaction
import traceback
import logging
log = logging.getLogger(__name__)
#region Custom HTTP Errors and Exceptions
#view_config(context=HTTPNotFound, renderer='HTTPNotFound.mako')
def notfound(request):
if not 'favicon' in str(request.url):
log.error('404 not found: {0}'.format(str(request.url)))
request.response.status_int = 404
return {}
I think you should be able to redirect to a view from within there.
I have a helper method in a Flask app that is used by several endpoints to get a resource. To avoid having multiple redirect_url calls everywhere, I want to be able to redirect from just this helper method. Throwing a RequestRedirect exception as shown here correctly returns a 301 response, but doesn't set the Content-Location error. To get around this, I added a after_this_request hook that sets the url for that response.
This seems to work correctly, but I was wondering if theres a more elegant way to go about it.
Anonymized helper method:
def get_resource(resource_id):
try:
# Some logic
except:
#after_this_request
def add_header(response):
response.headers['Content-Location'] = url
return response
raise RequestRedirect(new_url='/')
If it is outside of your api, typically you would redirect to a 404 page. Here's a sample:
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
So, I have a flask application that works well when it's not deployed. Imagine it has pages for /index/ and /home/ and /home/field/. Now that I have deployed the app using Apache and mod_wsgi, it needs to have a prefix for every URL.
Now, it should look like /newapp/index/ and /newapp/home/ and /newapp/home/field/.
So, I changed all of the URLs to include the new /newapp/ prefix, but the only URL that works with it is the original /index/ URL. All of the others return a
Not Found The requested URL was not found on the server.
in the browser when I click for that URL. I definitely handle that route in my main.py, so I don't know why it would not be found.
Anyone know what is going on?
EDIT: adding some code
Basically I changed all my code in main.py from:
Original:
#app.route('/')
#app.route('/index/', methods=['GET', 'POST'])
def index():
#Stuff
#app.route('/home/')
def farms():
#More stuff
#app.route('/home/<selector>')
def fields(selector):
#Further stuff
To....
New Code
#app.route('/newapp/')
#app.route('/newapp/index/', methods=['GET', 'POST'])
def index():
#Stuff
#app.route('/newapp/home/')
def farms():
#More stuff
#app.route('/newapp/home/<selector>')
def fields(selector):
#Further stuff
I did this because the domain I am using already has another Flask app, so I had to differentiate between the two. Also, I expect there to be more flask apps in the future, so this newapp will end up being an identifier for any given flask app.
I changed main.py as well has all of my hrefs in my templates. So, the hrefs went from
href=/index/
to
href=/newapp/index/
And, I get the error that I posted above whenever I try to click on a link
Further info:
So, checking out the apache error logs one error says, File does not exist: /var/www/flask_util.js, because in my main.py I call from flask_util_js import FlaskUtilJs. I'm not sure if this has anything to do with the URL routing, but it might
You don't need to add the prefix in your code.
Say you have code like
#app.route('/hi', methods = ['GET','POST'])
def myIndex():
return "Hello World!", 200
And you set your alias like to deploy it to www.myserver.com/app/
WSGIScriptAlias /app /var/www/myDir/myApp/app.wsgi
the server should automatically map www.myserver.com/app/hi to /hi in your application.
However if you set the mapping to
#app.route('/newapp/hi', methods = ['GET','POST'])
def myIndex():
return "Hello World!", 200
You WSGI app would only receive the call for /hi (server strips away the prefix) so it would find no matching Path and return not found.