I am preparing for a new project, and am testing out the Flask framework. Additionally, I am becoming more comfortable with hosting via Heroku.
First, I followed this tutorial: https://www.geeksforgeeks.org/deploy-python-flask-app-on-heroku/.
As I go forward I am experimenting with Flask and Heroku some more.
-
To run locally, run
app/main.py. In VSCode this can be done withF5. -
To push to the Heroku servers, simply push to the personal repository. On Heroku, I set it up to immediately run the version that is pushed to the main branch (if it passes CI, which is not yet set up).
-
The site is https://eflask-app-067.herokuapp.com/, and it runs indefinitely.
-
The file
.gitignoreinstructs git to ignore certain files, such as__pycache__folders which are generated by python to store some information. -
The files
PipfileandPipfile.lockwere generated through thepipenvcommand, and appear to give information on dependencies and the environment. -
The file
Procfileappears to tell the server what to run on startup; specifically, it runsgunicornand targets the app variable inapp/main.py. -
The file
runtime.txtis used by Heroku. It contains info regarding which version of Python to use. Only some are available, and the one reccomended by the tutorial does not work. -
The file
wsgi.py(alternatively,app.py) is the starting point for code execution. -
The folder
appwill contain code for the server to use, and resources like HTML, CSS, and images that are sent. -
The
.envfile (which is sensitive and not sent to github) contains environment variables for running the site locally. I believe I needed to installpython-dotenvfor the file to actually be loaded. Instead of a.envfile, Heroku uses config variables that can be configured through the CLI or through the site in Settings. If a variable is not present,os.getenv()will returnNone, so it is import to handle this if necessary.
-
Proper execution starts via a call to
app.run()(where app is the Flask instance created inmain.py). However, we need not call this function itself anywhere. For production, theProcfiletellsgunicornto run this variable, and VSCode (using flask) knows to run it as well. -
The
appvariable is set up inmain.py. Setting it up entails defining functions that are to be called at different times to generate the site's response. These functions are linked toappby the@app.route()decorator, which takes a string representing which url(s) should trigger that function. -
For debuging purposes, it is possible that an endpoint function can send raw HTML in the form of a string. The
\deprecatedendpoint does this, for example. -
Alternatively, you can write HTML in seperate files (in fact, you can write templates, but normal HTML also works). The
render_template()function generates the full response object to be sent. See\sampleor the homepage. -
You can also send a redirect message via
redirect(). Useurl_for()to create the right url (that function takes the name (string) of another endpoint function). See\redirect
-
Flask exposes two important variables to functions running in the
app.route()decorator:requestandsession. This resource is very useful for understanding these: https://flask.palletsprojects.com/en/2.0.x/quickstart/. -
requestcontains info about the request. For example, if the user sends a form, the info for that form can be obtained viarequest.form["form_item's_name"]. I used this to get input for the/loginroute. -
requestalso contains url arguments withrequest.args["param"], which I used to make the login page return you to your original target. -
sessionis a python dictionary, except it is aware of its own modification and sends / updates encrypted cookies when it is changed. You need to setapp.secret_keyto use it, however. I used this to store whether or not a user has logged in.
- Flask makes use of decorators, which are a very useful construct. In essence,
a decorating function wraps an old function, so that calls to the old function
call the wrapper, which (depending on context) may call the inner function.
See https://realpython.com/primer-on-python-decorators/ for more info.
- See the
require_passworddecorator inlogin.pyfor an example of how these can be useful. This decorator can be added to any endpoint function to force the user to login before accessing the endpoint.
- See the