Just like with any program, you will want to handle errors in your web application. By default, browsers handle your errors, but their default handling can be exceptionally ugly.
Besides general ugliness, the errors leave the user with fairly bad information, and, most importantly, no further call to action. Take a 404, for example. When you get a 404, it means the page you were trying to load just simply doesn't exist. The default 404 error gives no navigation back to where the user came from, and it is just a very unfriendly looking error. It almost certainly ruins the mood.
You've probably used a few websites and noticed that many websites appear to have custom errors like 404s that have various pictures. Try Google's 404 error by going to something like google.com/sfassfaa. A nice subtle robot that helps to lighten the mood when someone finds themselves on an error. Flask is no exception to allowing for custom errors. Not only can we handle things like HTTP 500, or 404 errors, but we can still also use the typical try/except syntax to handle other errors logically.
First, let's consider a simple 404, or "page not found" error. A 404 is very specific, and luckily handling this error is built into the Flask framework. First you just need a 404 function in the init file, then you can make a 404 template. You can have that 404 template extending your header, this way all of your typical CSS remains, your navbar will be there, and the general "feel" of the error will be a bit better.
from flask import Flask, render_template, flash from content_management import Content TOPIC_DICT = Content() app = Flask(__name__) @app.route('/') def homepage(): return render_template("main.html") @app.route('/dashboard/') def dashboard(): return render_template("dashboard.html", TOPIC_DICT = TOPIC_DICT) @app.errorhandler(404) def page_not_found(e): return render_template("404.html") if __name__ == "__main__": app.run()
File: __init__.py, server location: /var/www/PythonProgramming/PythonProgramming/__init__.py
Here, the only change is the page_not_found function.
Notice how this function is called by the wrapper above it. app.errorhandler is part of Flask, then the 404 is the specific error that we're looking to handle with whatever function we're wrapping.
In our case, we wrap the page_not_found function, using the actual error, e, as the parameter. Now, we just use a typical render_template function to render a 404.html template. That template doesn't exist yet, so let's make that.
{% extends "header.html" %} {% block body %} <p>Woops, that page doesn't exist! (404)</p> {% endblock %}
File: 404.html, server location: /var/www/PythonProgramming/PythonProgramming/templates/404.html
Simple example, but even this tiny bit of code is a vast improvement over the default.
How about other errors? Let's cause what would normally be an internal server error and see if we can handle that.
from flask import Flask, render_template from content_management import Content TOPIC_DICT = Content() app = Flask(__name__) @app.route('/') def homepage(): return render_template("main.html") @app.route('/dashboard/') def dashboard(): return render_template("dashboard.html", TOPIC_DICT = TOPIC_DICT) @app.route('/slashboard/') def slashboard(): return render_template("dashboard.html", TOPIC_DICT = shamwow) @app.errorhandler(404) def page_not_found(e): return render_template("404.html") if __name__ == "__main__": app.run()
File: __init__.py, server location: /var/www/PythonProgramming/PythonProgramming/__init__.py
Now we've got a new function that we're calling "slashboard." We just copy and pasted the dashboard function, changing the url and the function name. Don't forget to change the function name, or your internal server error will be for a totally different reason. It is easy to copy and paste functions to save time, but to also forget to actually change the function's name.
Instead of TOPIC_DICT = TOPIC_DICT, which is acceptable, we're going to say TOPIC_DICT = shamwow, where "shamwow" is a non-existent variable!
This could get ugly!
Save the code, restart apache, and you should find that you're getting a nasty error. Boo. So, what we can do is modify this slashboard function a bit:
@app.route('/slashboard/') def slashboard(): try: return render_template("dashboard.html", TOPIC_DICT = shamwow) except Exception as e: return(str(e))
So here we're using the traditional try/except logic that is a part of Python. If the try doesn't work, then we're catching all errors to the except statement, where we are returning the error in plain text.
Great, we caught the error, only we just replaced a very ugly message with a slightly less ugly, but still ugly, message. Simple enough though, you can probably already surmise the solution:
@app.route('/slashboard/') def slashboard(): try: return render_template("dashboard.html", TOPIC_DICT = shamwow) except Exception as e: return render_template("500.html", error = str(e))
So now we have a new file that we're referencing, 500.html. We pass one variable through, and that is the error.
Now we just need this 500.html page:
{% extends "header.html" %} {% block body %} <p>O dear, we got an error: {{ error }}</p> {% endblock %}
The 500.html page is basically the same as the 404 page in simplicity, we just have the specific error that occurred as well.
Alright, I think we have had our fill of errors. Let's move on to a new topic: Flask Flashing!