DOUG LLOYD: In a different video, we introduced you to Python and its syntax
and we talked all about how it can be used at the command line
to write programs that you would run from your terminal.
There's a lot more to Python than just that.
We can also use it to write web applications.
It is a really common use case to have website back
ends that are written in Python because Python contains
a lot more native functionality to support things like networking,
opening socket connections, maintaining connections between two
different locations on the internet.
And C can do these things too, but in C, it's really, really difficult
and really a lot of code.
In Python, because it is a more modern language that abstracts away
some of these kind of boring, tedious details of C,
it thus becomes a lot more straightforward
and a lot more tenable to write more complex web apps in Python
instead of using C.
In addition, there are a lot of what are called web frameworks that
make this even easier because they take some of the Python things
that we would have to do and abstract those away.
So basically you can think of a web framework
sort of like a library that's written in Python,
that is specialized in taking advantage and doing
some of the things in Python for you that you would otherwise
have to do yourself.
Creating a web server in Python is not all that many lines of code
to do it in just raw Python.
But it's a little tedious.
Not nearly as tedious as C. But using one of these different web frameworks.
For example, Django, Pyramid, or what we use in CS50, which is Flask,
makes it a lot easier.
Now, those frameworks are all great.
We're talking about Flask in CS50 specifically
because it is very lightweight and still quite feature-rich,
which means that it will work well on CS50 IDE
where you are using a cloud-based infrastructure,
and the amount of space and memory you have is limited by design.
Using the lightest weight web framework possible was really important.
So we've talked about HTML in the past and we know
that we can use HTML to build websites.
But there is one major limitation that HTML websites suffer from
and that is that they are static.
So imagine we want to create a website, for example,
that displays the current time, just the time in Cambridge, Mass,
displaying it to the latest minute, let's say.
This is some HTML that would do exactly that.
So the current time in Cambridge is 14:08.
So 2:08 PM.
This is great for a minute.
But at 2:09, it becomes not accurate anymore.
So if you're the webmaster and you have a page that's written entirely in HTML
and your job is to present an accurate website that
reflects the current time in Cambridge, every minute
you have to go through and update this page so that it is always
consistent and so that whenever a user visits the site,
they're getting the actual correct time.
This is awful.
You would not want to do this.
And if you were actually a webmaster and this was your job,
you probably wouldn't last too long because you'd
be literally just changing things.
And imagine if we were going to the nearest second or the nearest
millisecond, you wouldn't be able to actually even do it.
The only way to update our source in HTML
is to literally go in and edit our HTML.
If we incorporate Python into our code, though, we can be a lot more flexible
and we can allow our pages to become dynamic
without requiring any human intervention.
And that's ultimately our goal here, is to automate these processes for us
so that we don't have to think about them day
to day, getting buried in that minutia.
So we're going to do this specifically in Flask.
And here's an example of a web application in Flask
that would display the current not only time in Cambridge
but it would also display the current date, day of the week, year,
and it would display that time to the nearest ten thousandth of a second.
Just a couple of lines of code from Flask.
Import Flask, we'll talk about that in just a second.
Here, I'm just importing a couple of modules
that are also available in Python.
So Flask is one module available in Python.
Here, I'm importing the datetime module and specifically I'm
pulling one function from it, also called datetime.
And from the pytz or py timezone module, I'm
pulling one function called time zone.
Then I'm initiating my Flask application.
And then I'm basically using the datetime and timezone functions
from those two modules that I imported to figure out what the current time is
in the time zone America/New York.
New York is in the same time zone as Cambridge
and that's the standard time zone name.
So I'm just going to use that one.
So I'm figuring out exactly what the current date and time is
and assigning that to a variable in Python called now.
And then I'm returning some string where I'm plugging in whatever now is.
And apparently I'm doing that to app.route/.
We'll talk about all that in a second.
But basically I wrote this on a web page in Python in something
called application.py, specifically.
And then I ran this application and visited
the page that was generated from it, it would tell me
the current date and time to the nearest ten thousandth of a second.
If I refreshed, it would update it every time.
It wouldn't be static, it would become dynamic
and I wouldn't have to do any more intervention.
This would work for as long as my computer worked,
as long as the web server was running worked
to give me the current date and time.
And I, as the webmaster, can focus on much more fulfilling and fun things
than updating my HTML source every 60 seconds.
So getting started using Flask is really easy within CS50 IDE.
We first open up a Python file and in general, we're
going to call it application.py.
But you can call it whatever you want but in all these examples,
we're going to be referring to it as application.py.
The very first line of application.py is going to be the following.
From Flask, import capital F, Flask.
So flask with a lowercase f is the name of a module.
Capital F Flask is going to be the name of a function within that module.
In particular, it's going to be a class.
Generally, you may recall from our video on Python syntax,
that we indicate classes with a capital letter.
That's what we're doing here, we're importing the Flask class.
After we import it, we then need to initialize a Flask application.
You saw that on the previous code example as well.
App equals flask parentheses underscore underscore name underscore underscore.
Underscore underscore name underscore underscore is just
the name of the file.
So basically this is creating a flask application
based on whatever file this line of code appears in.
Which, again, is always going to be generally application.py.
So it's basically creating an app, a Flask application
from the application.py file.
And then from there, we just have to write
functions, which we're familiar with doing in Python,
to define the behavior of our application
when we do different things.
So here, for example, are two functions that I might write.
And you'll notice that this is not new.
This is just writing in Python.
We're not writing in anything special here.
I'm defining a function called index, whose sole purpose
is to return you are at the index page.
And I'm defining another function called sample,
whose sole purpose is to return the string you are on the sample page.
Now, how do I associate these functions with my site?
Well, what I can do is something like this.
This is called applying a decorator, and I'll talk about this in just a second.
But basically what it means here is if I go to my web applications home
page, which you may recall from our video on HTTP, is just slash.
So if I don't type anything else, it's going
to default to index.HTML or nothing.
It will show me you are at the index page.
If, however, I go to whatever my web applications address is slash sample,
it will not show me the index page, it will show me the sample page.
So basically what I'm doing here is I'm defining the behavior
that I want to appear on different pages within my flask application.
So again, these are called decorators.
And in Flask context, we're basically just associating a particular function
with executing when you visit a particular URL.
Decorators are actually not something that are native to Flask,
they're native to Python more generally.
But that goes beyond the scope of what we cover in the class.
But generally they are used to modify the behavior of a function
or associate a function with something.
But in Flask, we're going to use it specifically to associate functions
with visiting certain domains.
OK?
We also then need to--
So we've now written some code, the index and sample functions.
Now we want to run our Flask application.
We do that in three steps, the first two of which you only have to run once.
First thing you have to do is export the Flask app.
Flask app is a system variable and it's going
to become stored in the memory of your IDE specifically,
so that if you ever run an application again,
it knows exactly which application to run.
So we're basically just saving in memory somewhere the location
of our Flask application.
It's being stored in a system variable.
So export flask app equals application.py,
because that's the name of our file.
The second line is technically optional but it's recommended particularly
as you get started.
Export flask debug equals 1.
1 here just basically means true.
So basically you're going to be running it
so that when you run your flask application in your IDE,
you are seeing all of the things that it's doing in debug mode.
So if something goes wrong, it will get printed out to your terminal,
you'll see it.
It's not like your site will just crash and you won't know what happened.
And then after executing those two lines of code, again, in our IDE,
just executing those two commands, rather, in our IDE, flask run.
And then what will happen specifically in your IDE,
is it will take about a second to spin up
and then it'll give you a URL that you can click on
and visit, which will be the home page of your application.
Again, after the first time you get configured
with the particular application you want to run,
you can leave these two blue lines out, you won't need them again.
You can just continue to type flask run and it
will continue to run that same application over and over
until you no longer want to run it.
And then you would export a different application, export a different debug
mode, and so on.
So in addition to just running code as we
did before, just having it print out you are at the index
and you are at the sample page, we can also
pass data in to our Flask applications.
We can do this using HTTP get, you may recall, by passing in data via URL.
So I might write a function that looks a little something like this.
It's a function called show and instead of taking
no parameters like index and sample did earlier,
I'm accepting a parameter here called number.
And I'm returning you passed in, and then I'm
apparently going interpolate or stick in some number.
Where does that number come from?
Well, look at my decorator here.
@app.route slash show slash.
And those angle brackets are actually important,
we actually have to leave those in, number.
So that if I visited my application slash show slash 10,
the page would show you passed in 10.
If I went to slash show slash 50, it would say you passed in 50.
So it allows me to collect information using HTTP get
by having the user supply it via a URL.
We can also pass in data via HTML forms, which are transmitted not by get
but by something called post.
Now, by default, Flask is configured to only accept
HTTP get requests or information via the URL
so we have to modify a couple of things to make sure that Flask will also
respond to HTTP post requests, for example,
when data is submitted via a form.
So if you get to problem set 7 in CS50, which is CS50 finance,
you'll see that in our distribution code,
we have something that looks a little similar to this.
So this is where this is coming from if you want to take a look.
I've taken out a couple of things just to fit this four
lines of code on the slide here.
But this is some of the sample code that we give you
that is checking to see whether the user has provided
a user name in a particular field.
So notice that in addition in my decorator to saying where
the function should be associated, so in this case with slash login,
I'm also saying not only that, but you should
be accepting data via the get method or via the post method.
So that's how I explicitly call it out.
Then I'm defining my login function.
And I'm saying if not request.form.get username.
Using get here is unfortunately a side effect of Python.
That does not mean we're using the get method here.
Basically what I'm asking for is go and retrieve,
literally using get in that context.
Go and retrieve from the form the field called username.
And here I'm saying if it doesn't exist, apologize to the user.
Say they need supply a username.
So basically this is asking the question is the user name
field of whatever form the user submitted to get here, is that blank?
If it is, we need to apologize to the user and have them return something.
If not, we'll go to some more lines of code down below
and you're going to see those lines of code
in the distribution code for PSet 7, if you want to take a look.
Now, we can also vary the behavior of a function
depending on which type of HTTP request we got.
We can do one thing if we got a get request
and we can do one thing if we got a post request.
For example, if we got a get request, we might show them the form.
But if we got a post request, then we're going
to be expecting that they have provided some data via the forms.
We can use one URL to do two different things
depending on how the data came to us.
And that actually is what we do, that some of the code I
took out on the previous page.
But this code also appears in the login function for PSet 7.
If the request method was post, that was then
where I was checking to see whether the fields were all filled in.
Otherwise, what I actually do here, which an else here
implies if the request method is get, because I only
have two methods this function accepts, get and post.
Otherwise, what I'm doing is actually displaying
the form in the first place, the form that I expect them to type into.
Which submits to this page again in the hopes
that they will have submitted data that I could use.
And I would process in the post part of this function as opposed
to in the get part of this function.
So if request.method basically is allowing me to check how I got data.
Request is something that is part of Flask
and it will let me see whether I got data via get or via post
and allow me to do different things depending on which it was.
There are a lot of functions within the Flask module
that will be useful for you as you continue to develop applications.
So in addition to saying from Flask import
Flask at the beginning of your files, you
might say from Flask import Flask comma any of these.
And you'll leave out the parentheses when you're doing that part
but you'll use the parentheses when you're calling the functions.
URL underscore for.
So this allows me to define a function and have
a decorator associated with it.
And maybe that decorator specifies that the URL here
is really long or, for whatever reason, not that helpful.
What I can do here is instead of specifying
the exact URL I want to go to, I can say what
I want you to do here is go to the URL for whatever function it is.
So say my login function was associated with some URL that
was like 50 characters long.
Here, I could just pass in, instead of typing out
that 50 character long URL where I wanted to use it,
I could just say URL underscore for login.
And because I associate it with a decorator,
it'll just plug it in there instead.
So it's a way to kind of shorthand a couple of things.
Redirect, as you might expect, is Flask's function
that redirects you from one page to another.
Session is useful for HTTP session data.
As we've talked about get and post, you may recall that there's also a third.
And there are a few others but there's another thing
we would use called a session variable.
It's not necessarily an HTTP thing but it's usually stored in the headers
there as well.
And we can use that, for example, to track that a user is logged in.
And constantly check that they are logged in
even if they're going to different pages on our site.
So a session is used sort of like a global variable.
It's accessible by all pages.
If you establish a session, you can store data in the session for the user
as well.
Render template is used to create pages on your site that
mix HTML and Python together.
So I might render a template, for example,
where that template is the form that I want
to show to the user, the form I was talking about on an earlier slide.
I might have an HTML template where I've written the general form there.
And I might render a template and reference in the parentheses
there the HTML for the form that I was just talking about.
And you can do some other cool things too
where you mix HTML and Python together using
a language called Jinja, which is going to be
beyond the scope of this particular video.
But if you want to get more information about what
you can do in the Flask quickstart guide and you really can get started pretty
quickly with it, the URL is there.
And if you want to learn about Jinja and how
you can mix HTML and Python together to create basic templates where
you can maybe substitute a couple of different things
in depending on what the user has submitted via a get or post request.
You can get some information on Jinja there.
Jinja is Python-inspired syntax.
So some of the things that you'll be familiar with from Python syntax
will be relevant there.
But there are a couple of little twists as well.
And you can learn more about Jinja at that URL there as well.
I'm Doug Lloyd.
This is CS50.