This tutorial is out of date! Try my longer, updated Flask-SQLite webapp tutorial here
If we were normal people, going to make a normal website, we might start off our website with a real big header proclaiming how great it is. The HTML we’d write might look like this:
But since we’re professionals, and we’re data wranglers, and we’re specifically data wrangling school data, we’ll probably start it off with the name of a school.
But then eventually we’ll have to make one about a different school, which will have a completely different headline associated with it
and if we have several hundred high schools in NYC it is going to take a very long time, much less if we want to expand to the thousands and thousands of schools across America.
Luckily, we don’t have to write that HTML. Instead, we write Python code that writes the HTML.
That Python code looks into a database, finds the name of the school we’re looking at, and slaps the <h1>PS 15 Roberto Clemente</h1>
right there on the page. If we’re looking at a different school, it gets a different name from the database, and the HTML gets a different name inside of the <h1>
tag.
This is called the backend of a site. The frontend is all of the HTML and CSS and JavaScript that the user interacts with, while the backend is the hard work that puts that HTML & co. together.
The backend can be any sort of programming language, and can be more or less complicated based on what it’s intended to do. Today we’ve decided we’re going with Python, and we’re using a rather simple framework called Flask
Flask is a web microframework built in Python.
Another popular web framework you might have heard of is Ruby on Rails (which, of course, uses Ruby).
While you can put everything in your Flask project into a single file, it’s most always better to organize it into multiple files - put your Python code over here, put your HTML templates over there, some other stuff somewhere else.
Our project is going to be called nyc-schools
. Add a folder called static
and another one called templates
.
nyc-schools/
app.py
static/
templates/
static
is for files that aren’t dynamically generated, like images and JavaScript files and the like.
templates
is the templated versions of the dynamically generated web pages (i.e., the previously-mentioned <h1>
with a placeholder inside of it).
app.py
is our application file. It should contain the following code:
From terminal, in the nyc-schools
directory, run the command
And then do me the favor of visiting http://127.0.0.1:5000 to check out your freshly minted web application.
So you know how we mashed up a bunch of HTML in the “Hello world” section? That’s horrid, and we should be drawn and quartered for it. HTML belongs in an .html
file, and we’re going to put it there before anyone notices.
Add a file called index.html
into your templates
folder and have it contain the text <h1>Hello world</h1>
. We’re going to render that page instead of just sending back some text, which takes two changes:
Alter app.py
’s index function to read as follows
Add a new import line to the top of app.py
Now refresh. Cool, right? How nothing changes? render_template
is just reaching down into the templates/
directory, grabbing index.html
, and rendering it instead of the text we had there before.
To make use of this (kind of), let’s edit the code in index.html just to make a list of a few schools.
Refresh, rejoice.
Let’s say you have a cool variable in our application, like what we think the number of schools is in NYC.
You can actually send that value to index.html
, and then use it there to fill in empty spots in the template.
First we’ll edit our render_template
to send the information to the template.
Then we’ll edit our index.html
to use the variable, by using `` as a placeholder, with the variable name inside.
But that number doesn’t seem quite right. How are we going to change it?
A database is going to be the saving grace of this project - by pulling information out of the database, we don’t have to guess at the number of schools, nor do we have to type each and every one of their names out. It’s a paradise!
We’re going to use our models.py
file from the peewee tutorial - go ahead and copy it into the nyc-schools/
directory, along with schools.db
.
NOTE: If you don’t have the files, you can download them here: models.py and schools.db.
Using our database in app.py
is the same as when we imported it to learn how peewee works. Add another import to the top of the file:
Now we can use School
and Score
just like we did before! In order to get an accurate count of the number of schools, we’re going to use School.select().count()
. It selects all of the schools, then laboriously counts them.
Refresh! Rejoice! 437, right?
I’m still angry about typing out all of those school names in the index.html
- peewee can help with that, as well. Instead of just sending boring variables like integers to the template, we can send an entire selection of schools.
Then in our index.html
, we can loop through them all and display the school_name
s.
Then edit our index()
to pull all of the schools out of the database. We’ll pull them down in alphabetical order.
Step three: Send them to the template
Now we have all the schools, we just need to send them to the template, and then use them in the template. Edit index
one more time to send them to the template:
Cool, ‘eh? But it just isn’t enough, I know. If we’re going to win a Pulitzer we need individual school pages.
If we take a look at our index
, there’s a suspicious line right about it:
@app.route('/')
is a route - a URL you can type in to get to a specific function in the Flask app. That one defines /
and tells Flask to execute index()
whenever someone runs across it. Let’s make another one!
And now you should be able to visit http://127.0.0.1:5000/schools/clemente and see that route run!
Of course, we should probably set up a template for it. Let’s call it school.html
and put it into templates/
.
And edit app.py
to point to the template:
Refresh to double-check it worked, and we’re on our way to the next step!