Full Stack Python Web Applications with Flask and SQLAlchemy
These are instructions for getting a Python web app up and running quickly with Flask. On Windows!! On MacOS/ Linux, commands differ slightly but can be easily found online.
Why Flask? A micro web framework written in Python. It’s doesn’t have a database abstraction layer or form validation, but it is quick and easy! Also it was written in 2010 by Armin Ronacher (at a very young age!).
Steps: as of 2020-07-08 16:13:
Step 1: Setting Up Virtualenv and Installing Packages:
- make sure Python 3+ installed with
python -V
- install
pip
if you don’t have it. - If you don’t have
virtualenv
, with pip,pip3 install virtualenv
, so that your packages are installed locally, in your virtual environment, rather than globally. This is better for code portability and collaboration. - Make a virtual environment with
virtualenv env
(you can name theenv
whatever you want, but I stick with env) - Select source with
env\Scripts\activate
, make sure you are running Powershell\CMD\WSL with admin privileges! You should be insideenv
now. - Now, inside your virtual environment, you can start installing libraries. Go ahead and
pip3 install flask flask-sqlalchemy
Step 2: Writing Your Application :
- Make a .py file,
MyApp.py
- Inside
MyApp.py
: - Import Flask
- refer to the app. with
MyApp = Flask(__name__)
- Set up routes, first, the index.
- Define the function for route. (Right now it’s just “Hello World”)
- In development, set debug = true. This will show any errors.
- Steps 2-7 are summarized here:
from flask import Flask
MyApp = Flask(__name__)
@MyApp.route('/')
def index():
return "Hello World"
# remember to be consistent with your spacing.
# I chose 2 spaces.
if __name__== "__main__":
MyApp.run(debug = True)
- make sure you’re still in
(env)
and run your code withpy MyApp.py
. - Navigate to
localhost:5000
to see your app. - Congratulations! You’re up and running !
Step 3: Customizing your app:
- It’s a good idea to use templates and html inheritance - Don’t Repeat Yourself. Make a
templates
folder, and astatic
folder.- Template will live in the former and css/static content will live in the latter.
- import
render_template
inMyApp.py
- Once imported, you can go into the
index()
function and callrender_template('index.html')
from your templates folder. After running your app, the homepage shold be updated. Now you know how to inject a template!
Step 3b: HTML Inheritance :
- Let’s make a template that is inherited by any other pages in the site we wish:
- Go to
templates
folder and make abase.html
file. - Write boilerplate html into your
base.html
. Good source for this is: html shell - Now let’s use Jinja2 syntax, full documentation here, since it’s based off Django templating. (Also, it’s the template engine for Flask!)
- insert
{% block head %}{% endblock %}
before end of head tag. - insert
{% block body %}{% endblock %}
before end of body tag. - Between these, this will be where content is inserted.
- Go to
- Your
base.html
should now resemble this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{% block head %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
- Now navigate back to
index.html
and clear it so that you can inherit frombase.html
. - Extend base by writing
{% extends `base.html` %}
(Don’t forget single quotes.) - Next, inject your styling into base by writing
{% block head %} <p> your content here</p> {% endblock %}
and similarly,{% block body %} <p> your content here</p> {% endblock %}
- Now your
index.html
template should be:
{% extends `base.html`%}
{% block head %}
<h1>This is my head!</h1>
{% endblock %}
{% block body %}
<p>And this is my body...</p>
{% endblock %}
&. Run your server and make sure the changes took effect.
Step 4: Static Content and CSS :
- To use Custom CSS, in the
static
folder, make acss
subfolder and amain.css
file inside the subfolder. Write your CSS here.(go wild!) - To link this stylesheet with your web app, go to
base.html
and :- in
<head></head>
before{% block head.....}
syntax, insert<link rel = "stylesheet" href="">
and useurl_for
for the href argument. So: - We can’t exactly hardcode a path to the stylesheet, use
url_for
function by :- importing
url_for
from Flask withfrom flask import url_for
- since we’re looking for the
static
endpoint, we will useurl_for('static', filename = 'path for main css inside static')
, so we write …
- importing
<link rel = "stylesheet" href="url_for('static', filename = 'css/main.css')">
- in
- For JavaScript files, it’s the same protocol.
**Step 5: HTTP Requests
- to use HTTP requests, first learn the general structure of one!
- skim this
- you will probably focus on using
GET
,POST
,PUT
,DELETE
- import requests
Step 6: Forms
- To have forms on your web app, install Flask-WTF for forms.
- in order to do this, when inside your
env
, install bypip3 install flask-wtf
- optional :if you have the time, read the source code, especially
form.py
- enlightening to see how the FlaskForm class was written! This step is completely optional. - optional: if you have the time, read the source code for
wtforms
as well, especially\fields\core.py
for a look at how the fieldsStringField, PasswordField
, etc, were created! Completely optional step, just for the nerds.
- in order to do this, when inside your
- Now you need to store a
SECRET KEY
. :- It’s good practice to have a separate configuration page for all your variables, but since this is presumably your first Flask app, and is probably not going into production, go ahead and write it in
MyApp.py
for simplicity. - Under
MyApp = Flask(__name__)
, write:app.config['SECRET KEY'] = 'veryGoodSecretHashOfYourChoice'
. If you can, generate it randomly!
- It’s good practice to have a separate configuration page for all your variables, but since this is presumably your first Flask app, and is probably not going into production, go ahead and write it in
- Form Creation:
- You need a class representing the model for your form, so I recommend creating a
forms.py
file/module. - Remember my class and variable names are merely educational, do not name your variables/classes the same way - use descriptive, useful names.
- In
forms.py
, :
- import flask-wtf and wtform fields with:
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField # put any field types you need here!
- create a class form model by :
class GoodNameForForm(FlaskForm): # specify fields you need here! make sure you've imported them. username = StringField('username') password = PasswordField('password') submit = SubmitField('Submit')
- You need a class representing the model for your form, so I recommend creating a
- Now that we’ve created a model class for the form, we need to render the HTML / view for it. Let’s stick with our habit of separating concerns and using HTML inheritance.
- First, make a separate HTML file to handle the form. Call it, with an appropriate, corresponding, name!!,
myform.html
- Next, inherit from the base html (or whatever you want to inherit from), and craft your form in your preferred way, using Jinja2 to render the strings with
{{...}}
, and remembering to render head, render body, endblock, etc commands as above :
<form action="" method="post"> <p> {{form.username.label}}<br> {{form.username(size=30)}} </p> <p> {{form.password.label}}<br> {{form.password(size=30)}} </p> <p> {{form.submit()}} </p> </form>
- First, make a separate HTML file to handle the form. Call it, with an appropriate, corresponding, name!!,
- Now that you’ve created the view, you actually want to render the template from your “controller”. Head back to
MyApp.py
.- First, import your module so you can use it with
from forms import
- Here in
MyApp.py
, create a route that takes you to your form. Use an appropriate name. ex: ``` python # creates the new route and defines the function to run @app.route(‘/register’) # creates registration form def register(): # creates a form objects using the class we created before! form = GoodNameForForm()
# for step 6b - check if form is submitted if form.is_submitted(): result = request.form return render_template(‘viewImPostingTo.html’, result=result)
# and for step 6, if form not submitted, render our form HTML template : return render_template(‘myform.html’, form=form) ```
- First, import your module so you can use it with
**Step 6b: Working with Form Data : **
- In our
register()
function, let’s extract form data. - First, check if form was submitted with
if form.is_submitted
- and that your methods for the route include
POST
. - Import
requests
- here, render any templates or do any actions you might want to do.
- The data you are receiving from your forms is an immutable dictionary, so you can even iterate through it in your corresponding HTML view.