BRIAN YU: OK, welcome back
everyone to Web Programming with Python and JavaScript. So in the past couple of weeks,
we've been looking at HTML and CSS, learning about how we can write code
that decides how our website ultimately looks by describing the
structure of the code and by using CSS to
describe the style the code to determine how our web page is styled. Today what we're going to do is
we're going to take the next step and start building some dynamic web
applications using a programming language called Python in order to build
web applications that are a little more powerful than what we can have just
by describing the contents of a web page using HTML, for instance. But before we can get the Flask,
we should talk a little bit about the language
that we're going to be using in order to create
those web applications, and that language is Python. And so Python has come in a
number of different versions. We're going to be in this class
using the latest version of Python, as of now, which is Python 3.6. And so Python is a
programming language that is an interpreted programming language. Meaning what we'll do is we'll be
writing code in the Python programming language. And then we'll run it
through what's called a Python interpreter, a program that
reads in Python code line by line, and interprets it, tries to parse
the Python, understand what it means, and then execute that code. And so what we'll do first before
we dive into the web programming part of this is take a look at
Python, just the language itself, get a feel for how the language works
and what the different components and features of the language are. And after that, we'll use
those skills using the tools that we can use in Python in order
to use that language to generate dynamic web applications of our own. So let's dive right in and take
a look at our first example of a program written in Python. And this program is Hello.py. The dot p-y extension is
just a common extension for names of files that are
files that contain Python code. So this piece of code
is called Hello.py. And it's just got one line. And that line is a print, and
then in parentheses and then in quotation marks,
the words hello world. And so this is a very
simple Python program. And let's try running this Python
program just to see what happens. And then we'll take a look at
how this is actually working. So in order to run a Python
program on the command line, I'll type the word Python to run
the Python interpreter, followed by the name of the Python
file that I want to run. So in this case, the name of
the Python file is hello dot py. And so if I type hello dot py and
press Return, just to say run hello dot py in Python, what I get is just
the words Hello World printed out to the terminal screen. And so that's all it does. A fairly simple program that
just prints out hello world. And if we take a look
at hello dot py, we can start to break down
what's happening here. This word print, this is a
function, just a word in Python that represents doing Something, In this
case printing something to the screen. And inside the parentheses is what's
called the function's argument, information we give
to the print function, in this case telling the print function
what it is that we want to print out. And so in this case, we have in the
parentheses in the "string", which is just a sequence of text "hello
world" meaning print out the words hello world to the
screen, and therefore when we ran hello dot py by
running Python, the result was that we got the words the
hello world printed to the screen. And so that was a fairly
straightforward Python program, just one line long that prints
something to the screen. Let's take a look at something
a little more sophisticated. So inside of a name
dot py, now here I have a Python program that's got two lines. And so let's break down
these lines one by one and get a sense for what's happening. Here line one, we define
a name, where name is just a variable, some name that we're
going to give it to a place where we can store data or information
inside of our Python program. And name is going to be set equal to
the result of this input function. And so input is a function
that in Python asks the user to type in input at the command line. And when they press Return,
whatever it is that they typed in, gets returned from the function. It's information that's
passed back from the function. And if you're familiar with
other programming languages, it's much the same idea. And so we ask the user to
type in their name presumably. That gets stored inside of
this variable called name. And now let's take a look at line two. What's happening here? Again, we're calling
that print function, the same function that we
called in hello dot py. But in particular what's
inside the parentheses is slightly different notation. So the first thing that's slightly
different is that the string-- the text enclosed in
double quotation marks-- begins with the letter F. This is a
new feature of Python version 3.6-- the latest version-- called the format
strings, which let us take a string, take text and substitute information
by filling in blanks in the string wherever we want to put a placeholder
for some other value, for instance. And so what that's
going to allow us to do is say something like print hello comma. And then these curly
braces surrounding the word name mean take the
variable name and plug it into this format string inserted here. So whatever name gets
typed in, that gets saved into this variable called name. And then when I print something out,
I'm printing out the word hello comma, and then here, we're going to
insert whatever that name was that was passed in via the input. So if I try to run this program
now by running Python name dot py-- because that's the name
of this Python file-- and I press Return,
nothing appears to happen. And the reason for that
is that on line one it's waiting for me to
provide some sort of input. Recall that line one, I have
name equals input this function. And so if I type in my name, for
example, Brian, then on the next line it says hello Brian. So name was my name. And then inside of the format string,
inside the print statement on line two, it substituted my name in where
these double curly braces were. And if I were to run this again, typing
in someone else's name like David, then the next line says hello
David, plugging in that new name into that format string as well. So that was an example
of variables in Python as well as format strings, which are
a special type of string in Python. Questions about that we've seen so far? Yeah? AUDIENCE: [INAUDIBLE]? BRIAN YU: Yes. So the question was can we also pass
in a name via command line argument? And yes, Python does have ways of
interpreting command line arguments. You'll have to use a separate
package in Python that allows you to deal with that. It's called the sys package, s-y-s. And using that package, you can
interpret command line arguments and do things with those
command line arguments. We won't explore those too
heavily in this course, because our focus is going to be to
quickly move away from the command line and start moving towards building
web applications in Python. But yes, you can in Python use command
line arguments to get information from the user as well. Other questions before we keep going on? So this name on line one
was the first example of what we're going to
call a variable in Python. Just a place in our Python code where
we can store data of different types. And so let's take a look at the
different types of information that we can store inside
of a Python variable, and just look at a couple
of examples of that. So right here what we have is a Python
program called variables dot py. And what this does is it defines
four different Python variables. And these variables all
have different types. And so on line one, I've defined
the variable i to be equal to 28. And now i is going to be a
variable that stores the number 28. But in particular, it's storing
a particular type of information. The number 28 is an integer,
where integers are 0, 1, 2, 3, 4, and the negative 1, negative
2, negative 3, et cetera. And so i in this case is
just an integer value. And so we see here that Python
can store integers as variables. And then we're going to print out that
i is 28, for instance in this case. And then on line four, I'm
defining a new variable called f, which is equal to 2.8. And so this shows you that Python
can store not only integers, but floating point values as well,
values that have a decimal in it. And so this is a different
type of variable altogether. And so that will print
out f is 2.8, for example. But it's not just numbers that
Python can store as variables. We saw in name dot py-- the
example from just a moment ago-- that we can use variables
to store strings as well, text that can be used in order
to store a name, for example, inside of a variable. And we can store other types as well. Down here line seven, we
see that b is set to true. So Python has a special
type called bool, which stands for Boolean values,
where a Boolean value is just a value that is either true or false. It represents where the something is
positive or negative, for instance. And Python has a special keyword
called True with a capital T that represents the Boolean value true. And likewise there's also a false
value that represents a false Boolean value as well. And finally, Python also
has a particular type called the None type, which only has
one possible value, just called a None. And a none type is just a way
in Python to represent the idea that a variable has no value. So if we want a variable that
doesn't have value for some reason, and we might see examples
later of when that could be useful or helpful
or practical, you'll often see capital N
None used to represent a kind of variable that just isn't
storing any information whatsoever. So if I were to run variables dot py,
what I get is that i is 28, f is 2.8, b is false, N is None. Note that I never told my program
that i is going to be an integer, or f is going to be a
floating point number, or b is going to be a Boolean value. Python figures this out for itself. When I say i equals 28, Python knows
that if I'm assigning the number 28 to i, then i must be in integer value. And so if you're familiar with
other languages like C or Java, where you're used to having
to explicitly write out the name of the type for
any particular variable, know that Python doesn't
require you to do that, and just lets you take a variable
and assign it to any given value without needing to specify explicitly
what the type of that value actually is. Questions about that so far? So let's take a look at
some of the other constructs that we can begin to build up by
using Python and its various language features. Let's take a look at conditions dot py. And so what we're
going to do here is say that we have a variable called x that's
set equal to some number, for example. Maybe the number 28,
just to take an example. And what we have here on line
three are conditional statements, if statements, which are
effectively branches in the code where depending upon whether or
not something is true or false, we can decide which code
you want to execute. So let's take a look at
what's happening here. We say on line three
if x is greater than 0, then anything indented underneath this
if statement, as we would call it, is code that will only run
if x is greater than 0. So if x is greater than 0, then
here's what's going to happen. All of these indented lines, in
which case now there's only one, we're going to print out
the string x is positive. Meanwhile, el if is short for else if. In other words, else otherwise
if x wasn't greater than 0, if x is less than 0, then let's
run this indented line here, print x is negative. Else otherwise, if it was neither
greater than 0, nor less than 0, there's only one remaining possibility. We can print out the fact that x is 0. And this indentation in Python
is something you'll see a lot. The indentation in Python
is actually required. Unlike several other
programming languages where indentation is
a style thing, where it's nice and helpful from a readability
perspective to include indentation, but it's not strictly necessary, in
Python this indentation is necessary. This is how you tell
the Python interpreter this is the code that is contained
inside of this if statement. This is the code that should run
if this if statement is true. So if I had multiple lines that I
wanted to run, if x were greater than 0 for instance, I would have multiple
lines all indented inside of that if statement as well. So if I were to go over here and run
this program now, rather than print out three things, because I
have three different print statements, if I run in conditions
dot py, I just see x is positive. Because it caught on that first if
condition, if x is greater than 0. And it printed out that x is positive. If x were negative 28 instead, and I ran
that same program, now x is negative. And likewise, if I had replaced
x with just 0 for instance, and run that again, now I just
see that x is 0, for instance. And so depending upon the
value of x, I can conditionally determine which way to go in the code. Questions about that so far? Let's keep going then. So thus far we've seen
examples of variables in Python that are able to store
single values, effectively, a single number, whether it's
integer or floating point number or a single Boolean
value, like true or false. But Python is very
good at also supporting storing sequences of data where
we have multiple values that are combined together under one name. And there are a bunch of
different ways to do that. So I'll show you sequences dot py now. And so in sequences
dot py, I've given you three examples of variables
of different types that are all sequences
of data in some form. So on line one, I have
a variable called name, which is just storing the string Alice. This is something
we've seen before where we have a string, which
is just text that's being stored inside of a variable. But one helpful way to think
about a string like the word Alice is that it's really just
a sequence of characters. It's the character capital A,
followed by the character lowercase, l followed by lowercase
i, c, e. et cetera. And this way of thinking
about a variable makes it easy to say what
if I wanted to just get the second character of the name,
or the third character of the name, for instance? You can treat that long
string as just a sequence of the individual constituent
parts that make it up. On line two you're looking
at an example of what's called a Python tuple, which is a
way of grouping a couple of values together in a single name. So if I wanted to store in Python
an xy coordinate, for example, like, on a graph if I wanted to store
a particular point on that graph, I might store it as follows,
where I say the coordinates are, and then in parentheses 10.0, 20.0. And so now both of those values
are stored as a single name, coordinates, as opposed
to needing to store two variables like a coordinates x
variable and a coordinates y variable, I can group them together and just
store them under a single name as well. And then finally on line
three, we see an example of what's called a Python list. And this is a very powerful
data type in Python. And a list is a data type that lets
us store a bunch of different values all together in one. And so here I have a list of
individual people's names. And so a list in Python is
denoted by the square brackets. So I open the square bracket
and then have the first thing in the list, which is the name Alice. And each of the elements in the
list are separated by commas. So Alice is the first
thing in this list, Bob is the second thing in the list,
Charlie is the third thing in the list. And so this is an example
of a list in Python that is all stored under
the variable name names. So using those lists we can begin
to perform operations on them. And one nice feature of Python is that
I don't just have to write a Python file and then run that Python file. And that's the only
way to run Python code. Python has a sort of a live
interpreter that lets me type code and see the result of it
happening in real time. So if I just type Python
instead of Python space, the name of a Python file
I want to run, what happens is that I've opened up the
Python interpreter, which is a place where I can line at a
time type of line of Python code and immediately see the result. And for our purposes this is
going to be pretty helpful. So you can do the exact same things
you could do in a Python file. I can say x equals 28, for
example and press Return. And now that line of Python is executed. And now if I were to
just type x, for example, it will show me that
the value of x is 28. And I can add any other
Python code that I want here. So if x is greater than 0,
then print x is positive. And now that prints out the
fact that x is positive. And so I'm able to run
Python code just like this. And the reason I'm doing
this is that we can begin to see some of the features
of Python data types like sequences by using the Python interpreter. So if I had a name equals
Alice, like I had before, the way that you access individual
elements of a Python sequence whether it's a string representing
a bunch of different characters or a tuple representing a
couple of different values or a list of even more values,
is that I can do name it, and then in square
brackets, the index that I want to access, where the first
thing in the sequence is index 0. So if I did name, square bracket
0, what is that going to be? Capital A. That's the first
thing in the string Alice. The very first character
is just that capital A. And likewise, name,
square bracket 1, that's going to be the second
character of Alice's name, where l is the second character. So it's sort of what we call
a zero index system, whereby the first thing in the string Alice
is number 0 and the second thing is number 1. And so that's a typical
computer science convention. It's true in other
programming languages as well. But know that square bracket 0 gets
you at the first thing in the sequence. Square bracket 1 is the second
thing, so on and so forth. And so if I had coordinates
equals 10.0, 20.0 for instance, I could use the
coordinates square brackets 0 to get it just the first
coordinate, and likewise, I could do coordinate square bracket 1
to get it just the second coordinate. And similarly, if I had a list of names
that was Alice and Bob and Charlie, then I could do names, square
brackets 0 to get at the first name, name square bracket 1 to get the
second name, and name square bracket 2 get at the third name. And what would happen if I
tried name square bracket 3? AUDIENCE: [INAUDIBLE]. BRIAN YU: So what I get is a
Python exception, effectively an error of some sort that tells
me that something went wrong. And in this case, the type of
the exception is index error. And it says index lists
index out of range. And so the interpretation of that
is that this index that I provided, this number, name square bracket
3 is out of the range of the list. There is no item in the names
list that has index number 3, and therefore Python
can't access it for me. And so if I'm trying to ask Python
or do something that it can't do, oftentimes I'll get an
exception of this form. And learning to become
familiar with these exceptions as you begin to see them as you
work with Python programming will help you to figure out where
the cause of the source of the area is, which can then help you
to then go back and debug and figure out what went wrong. So those were variables and different
types of data and conditions in Python. Let's take a look at some
of the other constructs that we can have in the Python
programming language, in particular, let's take a look at loops and how
we might repeat code multiple times. And so here in loops 0 dot
py i have just two lines. So on line one I say for i in range 5. And then on line two,
I'm printing out i. And so what this program is
effectively doing is on line one I'm saying let's take this variable
i and run it through this loop. This what we call a for loop
through a range of five numbers, ranging from 0 all the way up to
but not including the number 5, such that if I run the
loops 0 dot py what I get is that I get five numbers printed out,
0, and then 1, and then 2, and then 3, and then 4. Because this loop, this
loop happened five times. And each time the value of i changed. The first time it was 0. That it incremented to 1, and
then 2, and then 3, and then 4. And then it doesn't
include the final number 5. It goes up to, but not including the 5. And as a result I get numbers
printed out five times. If I wanted to print out
10 numbers, for instance, I could change range to range 10. And now running loop 0 dot py prints
out 0 all the way up through 9, for example. So that's an example of
a simple loop in Python. But Python supports other
types of loops as well, in particular, for
looping over a sequence. So we saw in the last example that we
have a bunch of different data types for representing sequences of data. We have strings that are
just individual characters. We have lists that are a
bunch of different values that are grouped together. And so if I look at loops
1 dot py now, you'll see what we have here is on line one
I had a final list, the same list as before. Names is equal to Alice, Bob, and
Charlie, a list of three strings. And then on line two, I have
a different style of for loop. I'm saying for name in names,
where the intuition here is that I'm going to be looping over
this names variable one at a time. And each time I'm going to call
each item in that list name. And that's just going to be the
name that I give to that variable. And then I'm going to print out
that name inside of the for loop. And notice that everything inside
the for loop, just like everything inside of my if condition needs to
be indented so that Python knows what code is contained
inside my for loop and what code is
outside of the for loop. And so if I now run Python
loops 1 dot py, what I get is Alice and then Bob and then Charlie,
one name at a time, one line at a time. Question? AUDIENCE: Do sequences need
to be all the same data type? BRIAN YU: Great question. So the question is, do sequences
need to be all of the same data type? The short answer is no. So in a list for example, I could have
a list, I'll just call it l for a list. That could be the number
28, and then the name Alice, and then the Boolean value true. That is technically a valid list. And I can say l square bracket 0 to
get it the first thing in the list. And 1 to get it the second, and 2
to get to the third, for instance. But generally speaking,
especially with lists, it's a good idea if different things
in the list are of the same type. It's often good design to have elements
of the list to be of the same type, because generally our lists are going
to have some sort of semantic meaning. It's going to be a list of names,
where all of the elements in the list should be strings. Or a list of numbers, where
all of the elements in the list should be integers. And it's helpful to be able to treat
each item in the list the same way. And we can only do that if items
in the list are of the same type. So while not strictly
necessary to have all the items in a list be of the same type,
it's often a good design idea to do so. Good question. Other questions before we move on? AUDIENCE: Could you skip the print
[INAUDIBLE] In the interpreted version, you don't have [INAUDIBLE]. BRIAN YU: So the question
is-- great question. The question is in the
interpreted version when I'm trying to display a
value, I didn't need the print. I just typed l0 instead
of print l0 in order to get the first thing in the list. This is something unique
to the Python interpreter that the interpreter if
I just type in a value, Python will tell me what's
currently stored in that value. But if I'm running a
Python program, then I do explicitly need that
print function in order to say this is a value that I
want to print out to the screen. So it's a slight difference between
the way the interpreter works live, versus when I'm running it
just through a Python file. I could equivalently type
print l0 in the interpreter. And that would produce the same results. But if I'm running it in a Python file,
like, a file that ends with dot py, then I need to have
the print line there. Good question. We'll take a quick look at some of
the other more advanced data types that exist in Python,
and then we'll move on to taking a look at a
couple of other things. So in addition to
supporting lists, which are an ordered sequence
of data where we have a first item and a second
item and a third item, Python also has support for other
collections of data as well. And so one of those
examples is a set where a set is just a collection of
items where no item shows up twice. And in particular, a set doesn't
have any particular order to it. So the only thing we care about
is a particular value in the set, or is a particular value not in the set? And so line one here, I've
said s is equal to set, where set is just a function
that creates an empty set for me. On line two, I've added
the number 1 to the set. On line three, I've added
the number 3 to the set. On line four, I've added
the number 5 to the set. And on line five, just for the fun of
it, I've added the number 3 to the set again. But the rules for a set is that
items in the set are unique. So if I try to add a number or a value
that's already in the set to the set again, then the result of that is
going to be no change to the set. And so if I print the
set out on the last line, and I run sets dot py,
what I get is just a set 1, 3, and 5, because those are
the only three numbers that are actually inside of that set. And so if ever you don't really care
about the order of the information, because sets doesn't
preserve which thing came first, second, third, fourth-- and I just care about which things are
inside of the set or not in the set-- then I can use this notation in
order to describe that as well. And one final data type we'll take
a look at are Python dictionaries. So dictionaries are yet another
data structure in Python which are used in order to map
certain values on to other values. And they're often used when
we want to try and indicate some sort of relationship between
a former value and a latter value. And so what we see in
dictionaries dot py here is an example where I
in my Python program might want to store the
ages of different people that I'm keeping track of. And so what I have here line one
is I've created a Python dictionary that maps what are
called keys to values. And in the case of my
ages dictionary, the key are all going to be the names of people. So in this case, I have the key Alice,
which is mapped to the value 22. And the semantic interpretation of
this is that Alice is 22 years old and Bob is 27 years old. And so what you'll notice
is that the syntax for that is that a dictionary is defined
by curly braces on either end. And then the key, which is some
value, followed by a colon, followed by what its value is. So Alice colon 22 means I'm going
to put Alice in my ages dictionary, and then set its value to be 22. And likewise, I'm putting
Bob into the dictionary and setting its value to be 27. And if I wanted to add something
to the dictionary later, I could do it like this on line two. I'm adding Charlie to
my ages dictionary. And Charlie is 30. That is the value that it is mapped to. And if I wanted to edit the value
of one of the variables later on, a line like this, ages
Alice plus equals 1 is a shorthand way of saying take
whatever Alice maps to in my age dictionary and increase its value by 1. It was formerly 22, now it should be 23. If I wanted to write this
out in a longer form, I could say ages Alice
equals ages Alice plus 1 to say update the value of ages
Alice, and set it equal to whatever ages Alice was a plus 1. But often a shorthand convention
for that is plus equals 1, meaning increase its value by 1. Those two lines are identical. And then finally at the end I'm
printing out this ages dictionary. And so if I run the
dictionaries dot py, what I get is this dictionary where Alice's
name is mapped to the number 23, Bob's name is mapped to the number 27,
Charlie's name is not to the number 30. And so that's an example
of a dictionary in Python that lets us map keys
and values together. And so these are all just a whole
bunch of different data types that exist in Python. Python is a large language with a bunch
of different features and data types that are built into the language. But these are some of the
most common data types, ones that will likely
frequently come up as you begin to work on programming in Python. Totally OK if you haven't
internalized all of what each one of those data structures is
and what's different about all of them just yet. But as we begin to design
web applications in Python, you'll hopefully start to
get a sense for when might it be appropriate to use a dictionary
in order to represent data, or use a list to represent data when
we're designing our web applications. So we've looked at data types in Python. Now let's take a look
at functions in Python. So here we'll open up functions dot
py and see what's going on here. So line one, I've defined
a new function in Python. We've seen built in functions like
the print function that prints things to the screen, or the input function
that gets input from the user. I'm now defining my own
function called square. So on line one I say def, meaning
I want to define a new function. This function is going
to be called square. And it's going to take one argument that
I'm arbitrarily just going to call x. Now just like in if statements,
we indented everything inside the if statement,
and in for loops we indented everything inside the loop. Inside of this definition
of my square function, I'm likewise, going to indent everything
and say that all the square function is going to do is that if
you hand me a number x, I am going to return back to you x
times x, the square of the number x, by taking the input value and
just multiplying it by itself. So this function, given
the number two will give me four, if I give it number three it
will give me nine, so on and so forth. And now on line four,
I'm running a for loop. I'm running a loop for i in range 10. And if we recall what numbers
is that going to range from? How many times will that loop run
from what number to what other number? 0 to 9, exactly. I start at 0, and it's going to
go up to, but not including 10. So it'll end up stopping at 9. And here's what we're
going to print out. We're going to print out something
squared is something else. And here, I'm using this
special dot format syntax. This is just a different way of
plugging in numbers into this string, in particular I'm saying this is going
to be a placeholder for the value i, and this is going to be a
placeholder for the square of i. So whatever i's value
is I want to plug it in to this first thing in the string. And the square of i is going to be
plugged in to this part of the string. And this is a slightly older way of
plugging in values into Python strings. And I'm showing it you here in case
you ever use a version of Python older than 3.6 where the formatted
strings, where we started strings with the letter f isn't supported. You can use this notation as well and
it will effectively do the same thing. So in this case we're looping
over the numbers from 0 to 9 and saying something
squared is something else. And I'm calling my square
function, the square function that I've defined up there. And so when I run this program
by running Python functions do py, what I get is a loop that runs 10
times 0 squared is 0, 1 squared is 1, 2 squared is 4, all the
way down to 9 squared is 81, where each time I took
this input value i and called my square function, which gave me
back a number like 81, for example. And this was the code to do that. Questions about functions or
anything we've seen so far in the Python programming language? Yeah? AUDIENCE: Do you have to define
function before you use it? Does it always have to go first? BRIAN YU: Great question. So the question is, do I need to
define the function before I use it? And in general, Python needs to know
about the existence of some name before you use it. So in this case, if I were
to take the square function and move it underneath
the for loop, for example, watch what will happen when I try
and run functions do py again. It gives me a name error. This is another exception. We saw the index error
before where I was trying to access some particular part
of the list that wasn't supported. And in this case, I'm getting a name
error saying square is not defined, meaning Python doesn't
know what square is. And the reason is that
I've hit line two, where I'm trying to call this square function
but Python's reading my file from top to bottom. And so square as a function
doesn't get defined until later on. So we do need it earlier, but we'll see
in just a moment how we can actually get around that issue and actually have
the square function underneath if we wanted to. So those are functions in Python. And the nice thing about
functions in Python is that once you write them once in one
file, you can use them in other files as well. And so you can use Python functions that
you've written yourself in other files, and you can also use functions
that other people have written in their own files in your own files
by referring to a function that exists in some other file. So I'll show you an
example of how that works. And this is going to be in
a file called modules do py. And so in modules dot py
what I'm doing is on line one I'm saying from functions import square. In other words, from this
functions do py file that I have, I want to import into the file the
name square, which in this case is a function back to modules dot py. From functions import a square function
and then print out the square of 10. So I didn't explicitly define the square
function inside of modules dot py, but I'm using it because I was
able to import it from functions. So any guesses as to what will happen
if I now run Python modules dot py? Where modules the pie is
importing square from functions and then printing out
the square root of 10? We wanted to print out 100. That's what we would like to happen. What actually happens is that
it prints out 0 squared is 0, 1 squared is 1, so on and so forth. And only after all of that, then
it prints out the number 100. So the number 100 is what we wanted,
but why did the rest of the stuff get printed out? AUDIENCE: It executes still. BRIAN YU: Yeah, it executed this code
that was originally inside of functions do py, this for loop that I defined
alongside the square function. And the reason why is that when I tried
to import from this function's file, it went through the function's
file going through each line. And when it hit that
for loop, it decided to just run that for loop for me. And so that's probably not
quite what I want to happen. I would like for someone to be
able to import the square function from my functions file
without them needing to then run all of the code inside
of the main part of my functions file automatically. And so one common solution to this
in Python is to put all of the code that I want to run only when I
actually run this functions file inside of its own function. And this is generally
called a main function, which will be just the
main function that runs when I try and run functions dot py. I've taken everything
and I've indented it to say this is all code that's going
to be inside of the main function. And then the last thing I need
is a bit of special syntax that you don't need to
worry about too much. But effectively what I'm saying
here is if name equals main-- in other words, if I am currently
running this particular file, that's how you should
interpret that line-- then run the main function. And so it's a little
bit of added complexity. But the reason for this
added complexity is that now when I run
the functions dot py, I still get 0 through 9 printed
out just as normal like I want to. But if I run modules dot py, the one
that was importing the square function and then just calling
the square root of 10-- oops. Python modules dot py-- then what I get is just
the number 100 because that is the result of calling
square on the number 10. And it didn't call any of this code. It didn't run any of the code that
was only inside of the main function. It only ran the code that was explicitly
asked to be run, which in this case, was calling for the square of 10. So that was an example of how we can
import functions from other places in order to use them. And we'll soon see when we
start moving to web development and writing web applications
in Python, that this will be really important for us,
that there are functions that do things in web applications that other
people have written that we would like to use, that we can
import from other people that they have written without
needing to write it ourselves. And we can take advantage
of those functions and effectively stand on the
shoulders of others in order to build web applications that take
advantage of those existing features. Questions about anything else before
we look at one last feature of Python, before diving back into web programming? Last thing we'll take a
look at is Python classes. And so this is something that will
become more relevant next week. But we're going to take a look at it
now just to get a preview and a taste for what it's like. Python classes are a way of defining
entirely new types in Python. So Python has a built in
type for representing lists. It has a built in type for strings. It has a built in type
for Boolean values, but it doesn't have a built in type
for representing a point in space. We could use a tuple, of
course, like we saw before, just some number comma some other value. But here is a way of
me explicitly creating a new type in Python called a point. And here's the way it works. So on line one I'm saying I'm defining
a new class of things called points. And on line two I have
this special init function. And the init function in
Python is a way of saying when I create a new point,
what information do I need? And in particular, I
need self, which is just going to be a variable that
represents the point itself, the object that I'm creating, and
then I need an x value and a y value. And so when I create a new
point, what should I do? Self dot x equals x is
my way of saying self is that name, referring to the
point object that I've just created. And dot x is my way of
saying, I want to access a particular attribute of the self,
of the point that I've created. In particular, I want to set
self x attribute to whatever this x value is that's being passed in. That way, when I create a new point,
I'm storing that x value inside of self dot x. And likewise, I'm storing the y value
of the point inside of self dot y. And so when I actually use this is on
something like line six where I say p is equal to point 3,5. That is going to create
a brand new point, calling this init function that gets
called anytime it create a new point. And it's going to set p's
x value to be whatever get passed in at x, which is 3, and set
p's y value to be whatever was passed in as the y value, in this case 5. And now if I print out
p.x and p.y, that's going to take this point to object
and access whatever its x attribute is and whatever its y's attribute
is and print out those values. And so we'll take a look at that. If I run the classes dot py
and press Return, what I get is 3 on the first line and
then 5 on the next line. Because I first decided to print
out the x value of my point p. And after that, decided to print out
the y value of my point p as well. And so that printed out 3 as the
x value and 5 as the y value. And so that would be how we would create
classes entirely new types in Python as well. And so that was a lot of overview
of the Python programming language. It's a big language. There's a lot of stuff going on. We looked at different types
of variables and data types and conditions and loops
and functions and classes. Totally OK if this is all new to you,
but hopefully some of the concepts seem familiar or reminiscent
of programming languages that you may have used before. But we'll take a short break now. And after we come back
from the break, we'll talk about how to begin to use
some of these language features in order to actually build
web applications that are living on the internet. So we'll take a short break
and then we'll come back. Welcome back. So we just got a whirlwind tour of
the Python programming language. And now what we're going to
do is use Python to begin to build some dynamic web applications. And so before we get there, I
just want to take a brief moment to talk about HTTP. HTTP, hypertext transfer
protocol, which is the system that we're going to be using
that the website and the internet uses in order to
interact and communicate between computers and servers. And so the general idea or
the model to get in your head is that when you type in a website
and press Return, what that's doing is sending an HTTP
request to some server. If I type google.com
and press Return, I'm sending an HTTP request
to Google's server. Google's server receives that
request, needs to figure out some way to interpret that request. What am I asking for? What am I searching for? Am I searching for news or
images or something else? It figures out what's
going on in that request. Figures out what information
to give back to me, and then sends me back and HTTP response that
contains the information that my web browser then receives and then
displays on a page in Chrome or Safari or whatever web browser
that it happen to be using. And so what we're going
to be doing now as we go about building web
applications, is writing code that will take care of
that server side processing. Receiving requests, figuring out what
those requests they're dealing with and what they're asking for, and
figuring out what response to then give back to the user. And in order to do that,
we're going to be using flask. Flask as a micro framework
written in Python. What that effectively
means is that flask is some code already written for us
in Python that makes it easy to get up and running with a simple
web application that has a lot of features that can be
useful as we go about developing web applications, as we'll
soon see in a moment. And so flask makes the process of
designing a web application relatively easy, and lets us focus
really on what users are requesting and what
sort of response that we want to provide back to the user
after that request has been made. So let's take a brief look at a
first web application in flask. And this is going to be
inside of the first directory. And so flask code is generally
stored inside of a file called application dot py is going to
be the main file of a flask application. And here is the code that we need in
order to run this flask application, in order to run a basic
web application that we can serve as if it were a website. So on line one we have
from flask import flask. Just like before, when we were
importing that square function from the other file that
I had created, here we're importing flask, which
is just going to be a way of creating a flask web
server from this flask module that exists somewhere else. Someone else wrote the flask module. You can install it for free. And what we're doing on line one is
just saying that in this Python file, we want to use that flask module. Now what are we doing? On line three-- this extra line is
just there for aesthetic purposes. It doesn't serve a real purpose-- we're saying app is equal to
flask underscore, underscore name underscore, underscore. And what that's doing is saying I
want to create a new web application. And I want this web application
to be a flask web application, where underscore, underscore a name is
just representing this current file, that this file is going to
represent my web application. Then on line five, this is
where things get interesting. At app dot route and then slash. So flask is designed in terms
of routes, where a route is just part of the URL you type
in order to determine which page you want to request. And so this slash just
represents the default page. If I go to a website slash and
then nothing else after the flash, that is the default page
of the website that I just want to access when I access the web
page for the first time, for instance. And what line five is
saying, app dot route slash, is that when the user goes
to just slash on my website, goes to that default route, the
function immediately below it is the function that I want to run. This is a special line
called a decorator. No need to worry too much
about exactly how that works. But the idea is that I am
tying this function immediately underneath app dot route slash to
this slash, so that when I go to slash is the function that's going to run. This is a Python function
just called index. And all my index function is
doing is returning the string hello world, just returning that text. So this is a very simple seven line
web application written in Python. And let's try and run it now. So in order to run a flask application,
I'm going to go into the directory where that application is located,
in this case, it's called first. And I'm going to run flask run, where
flask is a web server that I'm going to just run in this current directory. So I type flask run. And what I get is I'm now serving
the flask app application. And I'm running it on
this particular URL. And so if I take this URL and paste it
into a web browser for instance, what I get is just the words hello world. I went to the default
route on my website. I just pressed Return. And the result is that this
text is what came back to me. This is the response
that flask produced. And it was produced because of
this line, this return hello world line, that happened whenever someone
went to the slash route on my website. If this had instead been hello
world with extra exclamation points for instance-- if I save
that, and I refresh the page, now those extra
exclamation points appear. So by editing my Python
code, this flask code, that I'm able to change the
way that my website looks. Questions about that very
simple first web application that we've been able to
create with just a couple of lines of code using Python and flask? Yeah? AUDIENCE: Does flask know to look for
a file callled application dot py? BRIAN YU: Great question. Does flask know to look for an
application called application dot py? Not out of the box necessarily. So what might happen is if you
try and just run a flask run, you might get an error that says
flask doesn't know where to look for your particular application. And the reason why is that
flask relies on what's called an environment variable,
a variable that's set inside of your terminal to know
what file to be looking for as the source of the application. I've already sent my application
to be application dot py. But if you're running
for the first time, you might need a line like
export flask underscore app equals application dot py. And all that line is doing is saying
set the environment variable flask app to be application dot py. In other words, tell
flask that the file that I want to run this
application from is a file called application do py, which
is just the general convention. But depending upon what
system you're using, that may or may not be
set automatically for you. So you may need to explicitly
tell flask application do py is what you want to use. Good question. AUDIENCE: So was it the
line that said [INAUDIBLE] or was it environment variable? BRIAN YU: Good question. So did I not have to do that? I have my terminal configured such that
it will automatically run that line. It will automatically set
the environment variable. And we can give you instructions
for how to do that as well. But otherwise, you can just need to
set the environment variable yourself. AUDIENCE: But there's also y in the-- the application up higher that
said app equals [INAUDIBLE] BRIAN YU: Good question. So what's this line doing? So all this line is doing
is it doesn't have anything to do with telling flask
which application to run. This is just us creating
a new variable that is going to be the source of this web
application called app such that later I can tie specific functions to it. So I created this flask
variable called app. And using that app, I'm
now able to say when someone goes to this route this is
the function that I want to run. And it it's only used
inside of this file to determine what routes get called and
what functions get called as a result. Good questions though. So that was our first web application. It just returned some basic text
when we go to the web application. But that's not all quite all
that interesting just yet. So let's try and make things a little
more interesting, in particular, let's try and add a couple routes. So let's go into routes 0
and take a look at this code. So inside of application dot py
here, we see that up until line seven everything is identical. I had app route slash. And when that happens, I want
to run this index function that just returns the text hello world. But here on line nine I've added
a special additional route, app dot route slash David. And when I go to slash
David on my web application, it's going to call this David function. And what that does is return
the words hello David. So what's the result of that going to
be when I run my flask application? Well, if I run flask
run and then go back to this URL, this local
URL just on my website, it just says hello world for now. It just shows me that default route. But if I go into my URL bar and
change the URL from just the default route to this URL slash David, for
example and press Return there, now it changes to hello David. So I have two separate routes now
running on my web application. If I just go to the default
route, it says hello world. If I go to slash David,
then it says hello David. And that's all because using
flask I was able to tie specific functions to particular
routes of my web application. Questions about how that's
been able to work so far? So if I wanted to add additional
routes to do additional things, I could certainly do that. If I wanted to add a different route
to say hello to Maria, for example, I could add another
line that app dot route slash Maria, define a new function
called Maria, in which case, I would return hello Maria. And now if I run-- go to slash Maria on
my website, it's going to say hello Maria, because
I've added that additional one. But of course, this isn't
going to work for anyone. If I try and type my
own name, slash Brian, I get a not found error
because I've typed in a route, but my flask application doesn't
know how to deal with that route yet. It doesn't know how to deal with
my name Brian, because I only have routes for the default route, the
slash David route, and the slash Maria route. My name isn't one of them. So what if I want to make my flask
application a little more powerful, and let it say hello to anyone,
not just David and not just Maria? Let's take a look now at routes 1,
which will be an example of just that. So inside of application dot py here's
what we have going on inside of routes 1. Up until line 7,
everything is identical. We're just saying hello world if
I go to the default slash route. But where things get
interesting is down here line 9. I have app dot route slash, and then
in angled brackets string colon name. This is not a particular route
that someone is going to, but a template for a whole
generalized set of routes that people could potentially go
for it such that whenever anyone goes to slash and then any string-- and we're going to
call that string name-- it's going to call this hello function. And this hello function
takes as an argument this name, a name that
gets passed in via the URL that the user typed
into their web browser. And what happens here? Well, I'm going to return this
formatted string hello comma, and then name in the curly braces,
which is very reminiscent of one of those early Python files
that we looked at way back at the beginning of lecture
where I asked for a name to be typed in just at the command
line and then printed out hello name. This is exactly the same line, but it's
contained inside of one of these flask routes now such that this
route is going to capture any string that I type in as a name
instead of just David or just Maria. So if I now head over here and run
this application by typing flask run, and now I go to just the default
route, it says hello world. But if I instead go to slash
David, it says hello David. I go to slash Maria,
it says hello Maria. And I go to slash Brian,
it says hello Brian. It's able to take any
string that I type in, and just return hello
to whoever that is. So I've already been able to
create a dynamic web application. I didn't have to create a separate
HTML web page for each different person that I would want to say hello to. Just depending upon what's
passed into the URL, I'm now able to create a dynamic
web application that can say hello to anyone, hypothetically. And the beauty of this is that
this is all just Python code. So anything you can do in Python,
you can edit application dot py to reflect the changes in
order to update the website or update values of things to
be whatever you want them to be. So for instance, Python
strings have a method, a function that you can call upon them
called capitalize that takes a name and capitalizes the first
letter of it, for example. So if I, in my hello function, just
said name equals name dot capitalize, what that's going to do is that if
I type in a name that's the URL, it's going to first capitalize that
name and then return hello that name. So before I type in slash Brian, it
said hello brian with a lowercase b. I refresh the page now,
now the B is capitalized because I've added this line 11 that
just capitalizes that name for you before returning it back to the user. Questions about routes that
we've seen so far in flask? Or how the applications work? Let's take a look at some of the other
features that we can have in flask. And the first thing
that we'll probably note is that these web pages are
very, very simple so far. Right now all they do is
display some basic text. And of course, we could add
whatever HTML that we want to this. If I wanted hello Brian to be a heading
for example, instead of just plain text, I could return instead of hello
name, like, H1 and then slash H1. If we recall from the
HTML lecture, H1 is a way of making a big bold
heading at the top of the page. And so if I return those H1
tags surrounding hello name, now I when I refresh this page,
hello Brian appears big and bold. I'm able to use whatever
HTML content I want in order to return that information back
to the user when they see it in their web browser. But of course, the HTML pages that you
guys created in project 0 or HTML pages you might have created in other contexts
are likely much more complicated than what could reasonably
fit in just a single string. You can make it very, very long. But that's quickly going
to start to get messy. So what we want to do is organize our
flask application such that we can put HTML in HTML files, .html files just
like you were using for project 0, but somehow tie those
html files into flask. Tell flask to use those html files
that we've already created in order to return something back to the user. So let's take a look
now at another example. Here, inside of application .html,
here is what we have going on. From flask we import flask. And we're also importing a second thing. In addition to just
importing flask, we're importing a function in a
flask called render template. And we'll see why that's going to
become useful in just a moment. Line 3 is exactly the same so far. We just have app equals flask name. Then on line 5 we create our
default route, app.route slash, then the index function. And instead of returning
a string, just text that we want to display
to the user, I'm returning render template and then index.html. And what that's telling flask
to do is take an index.html file and render that and
display it to the user instead of just displaying
text, plain text. So if you look at the
structure of where I have my files, in the same folder
that I have my application.py file I also have this templates directory. And inside of this templates directory
I have a document called index.html. And if I open up index.html,
here's what it looks like. It looks like an HTML file that's
got a title that says my web page. And inside the body it
just says hello world. So what will now happen if I try
and run this web application? I go to that URL, and now
it displays hello world. And if I click and view the
page source of this web page, I can see the html content to that
web page is the same as index.html. So what I've effectively done
here is, via a round about way using flask and Python,
allowed us to just display an HTML page in the same way
that you've been doing already, just by writing the contents
into the html itself and then opening up that HTML document. Questions about how we were
able to render that HTML file? AUDIENCE: Can you just give any function
the index or whatever-- yeah, there. BRIAN YU: As index.html? AUDIENCE: No, no. [INAUDIBLE] BRIAN YU: Oh, good question. So what is the logic behind
the name of this function? Does it have to be called index? The answer is no. Your functions can be
called whatever you want. But often times later
on we'll see how it can be helpful to refer to a particular
route by the name of the function. And so making sure that
the names of your functions are logical or meaningful in
some way is usually a good idea. But this could be called
anything theoretically. Yeah? AUDIENCE: Index.html
was in a subdirectory. Was it searched
exhaustively [INAUDIBLE]?? BRIAN YU: Good question. So the question is how
does it find index.html? Where does it know to look? Flask is only going to
look immediately inside of a subdirectory called templates. So I have to have in the same
folder as application.py a directory called templates, inside
of which is index.html. And that is the only
place that flask will know to look for those
individual HTML files. Good question. So it doesn't seem like so far
that we've gained a whole lot. We were able to do the
differences in routes in order to say hello to different people. And that was something that
we couldn't do with just HTML. But so far what we've done now
is just created an HTML page that we're now displaying to the user. And we haven't added a whole lot. So let's try and use Python to begin to
add some new features to this website that we didn't have before. So let's take a look at variable 0. So inside of variable
0, what I have here is something a little bit different. So first couple of lines of the same. On my default route, I'm defining
a variable called headline, which is set equal to hello world. And now on my next line, return
render template-- before, I just said return the index.html template. That is the html content
that I want the user to see. But this kind of added an extra line. I've said return rendered
template index.html. But I've also said over here,
I've passed an additional argument to the rendered template function. I said in addition to
returning index.html, you should also know that I
want the variable headline to be defined and index.html to be
whatever headline this variable is equal to. So effectively, I am giving this
index.html knowledge of a new variable, a variable called headline,
which, is in this case, happens to be equal to this
Python variable called headline. So this is the variable that
will exist inside the HTML file. This is the variable that
exists inside the Python file. And very frequently, it's conventional
to give him the same name, although they don't need
to have the same name. So what is that going to do for me? What's inside of index.html? Let's take a look. So inside of index.html, inside
of that templates directory, here's what I have. HTML head, a title that says my website. It's the same as what we've seen before. Inside the body though is where
things get a little bit interesting. I have an H1 tag defining
a heading that will just appear at the top of the page. But then in this double
quotation marks I have this-- or double curly braces, rather, I
have double curly brace, headline, and then end double curly brace. And this you can think
of as a placeholder. In this HTML template
I've effectively said I have a headline that
I want to plug in here. And whatever the value of
the variable "headline" is, that is what I want to substitute
into this HTML template. So my HTML template
doesn't know in advance the headline is supposed to be
hello world or just hello or welcome or some other heading altogether. But as soon as I have a
variable called headline and I pass it into the
index.html file, then index.html will be rendered in such a
way that the headline will be filled in to that H1 tag. So if I run flask run right
now and go to that web page, it says hello world, not because I
had hello world inside of index.html. I don't. But because in my Python code, I've
defined this headline hello world. And that is what is getting passed
into my index.html template. So if I change this hello to
just hello without the world and refresh the page, now
that headline updates as well, because the timeout is
being dynamically generated, rendered by flask, depending upon
what I pass into it as variables. Headline is hello in that case. Questions about how that worked? Yeah? AUDIENCE: Can you go
back to index.html file? So the double [INAUDIBLE] BRIAN YU: This part? AUDIENCE: Yeah. So is that a proper
syntax of that [INAUDIBLE] BRIAN YU: Great question. So what is this double
curly brace index? It doesn't really look like HTML and it
doesn't really look like it's Python. In fact, it's entirely different,
what's called a templating language, an entirely separate
language called Jinja1, which is a standalone language. But it's a language that flask
uses in its html templates in order to make it easy to
dynamically generate web pages. And so we'll see a couple of
examples of this Jinja2 syntax. It's relatively intuitive. And it follows a very
similar style to Python. So it has a lot in common with
Python as you'll soon see. But effectively, all we
need to understand for now is that the double curly
braces are Jinja2's way of saying substitute something here. Put some value of a variable into
the template wherever that was. Great question though. So what's the advantage of
allowing me to just substitute some variable into the template
instead of just putting it into the template itself? Well, what I can do now is
I can say app.route slash bye, if I want to add a goodbye
route in addition to a hello route. And now I'll need to find a new function
called by where the headline is instead going to be goodbye. And now I can take that same
line, return render template index.html where headline
is equal to the headline, but this time headline
is goodbye instead. So now I refresh this page-- unexpected EOF. Let's save the file and try again. So we have the default
route that just says hello. But if I change the URL to be slash
bye instead, then what happens is I get goodbye to be displayed. And that's going to be the new heading. So I've used the same
index.html template. The only difference is I've changed
what value I pass in as the headline. And as a result, what appears in the
template and ultimately what appear appears in the html that
the user sees is different, depending upon what that was. Questions about that so far? Yeah? AUDIENCE: This Python count as back end? BRIAN YU: Does this Python
file come as back end? Yeah. What I've written here is
Python code for a back end web server, that is listening for a request
like, me typing in URL slash bye. It processes that request and returns
some response, in this case the HTML. So yes, this back end Python
code as you would term it. Yeah? AUDIENCE: And it updates dynamically? Like you don't have to start
the application [INAUDIBLE].. BRIAN YU: Good question. Does it update dynamically? In this case, yes. I have flask set to
what's called debug mode. And in debug mode flask will
automatically update any time I've made a change. But if you're not in debug
mode, then it typically won't unless you restart
the flask server. So there are different
configuration options for flask. But there is a way to let it auto
reload every time you make a change. Good question. So that is an example of it variables
that we've been able to see, where we're able to take values
and plug them into templates. But what else can we do with templates? How can we make things a
little bit more interesting? Well, to introduce this,
I thought we'd start by looking at an example of an
extremely simple website that does exist out there on the internet
that really just serves one purpose. And that website is isitChristmas.com. If I go to isitChristmas.com on today,
which happens to not be Christmas and I press Return, what I get is no. That's all the web site does. It just says no, it is not Christmas. And presumably, on Christmas it
would say yes, it is Christmas. So what if we wanted to write a similar
website for a different holiday, say New Year's for instance? And I want to write a isitnewyear's.com
type website that says no if it's not New Year's and yes if it is New Year's. How might we go about doing that? Well, we're going to need
some sort of condition. We want our template to display
yes if it is in fact, New Year's. And we want our template to
display no if it's not New Year's. So how might we go about doing that? Let's take a look now at conditions
and look at the code here. So this is application.py for
our is it New Year's website. So what I've done up
here is first import a Python module called date time. So Python has a bunch of different
modules that serve different purposes. And so depending on what
you're trying to do, different modules may serve
your needs differently. In this case, the date time module has
a very easy way to get the current date. And that's going to be
useful to me as I try and determine whether
it's New Year's or not. Then I import flask and render
template, just like I did before. I start my flask application. I add my default route, which is
going to call this index function. And here's what's happening here. I'm defining a variable
called now, which is set to datetime.datetime.now,
which is Python's way of getting the current date and time. And so that's going to be stored
inside of a variable called now. And now I'm defining a Boolean
variable called new year, which is going to be true if it is
New Year's and it's going to be false if it's not New Year's. And how do I know whether
it's New Year's or not? Well, if now.month, the month
of the current date and time, is equal to 1 and now.day is
equal to 1, then it's New Year's. So if both of these things are
true, the month is equal to and the day is equal to one, than
it's January 1st, New Year's is true. Otherwise, New Year's
is going to be false. And then finally, I'm
returning this template. Return render template index.html,
where the value new year is set equal to new year, which is
just this Boolean variable that I just created a moment ago. So I'm defining this
index.html template telling flask I want to render that template. And I'm giving it this
Boolean information of whether or not it is a new year or not. And depending upon whether
it's in New Year or not, that's going to determine what
I want the template to display. And so let's look at
index.html and figure out how it's going to deal with this new
year variable that I've defined here, that I'm passing in to the template. Let's look at index.html. So it's a fairly simple html web page. Inside the head I've got a title
that just says is it New Year? I've got some styling. And the only styling is that I
want everything to be centered. And here's the body. And here's what's going on in
also the Jinja2 templating syntax. I have this curly brace
percent sign, which is Jinja2's way of introducing
Python like syntax for conditions into the html file. I want my html file to have if's and
else's is in the same way that Python has if's and else's. And Jinja2 alongside flask lets us
do that by using this similar syntax. So inside a curly brace percentage
sign I say if new year-- in other words, if it is
in fact, the new year, then here's the HTML
that I want to display. Yes, happy new year. Else, if it's not New Year's then
I have this H1 that just says no, it's not New Year's. And then end they have to signify
the end of the if statement. So this looks slightly different
from just regular Python, but the words are the same. If and else, for instance, those are
the same keywords that you would use. And this is Jinja2's way of
saying I want to conditionally use different html content depending
upon the values of variables that I'm passing into the template. So if New Year's is
true, this is the html that should be rendered to the user. Otherwise, this is the html
that should be rendered instead. And so I'm able to dynamically
generate different HD, depending upon the values of these variables. So if I run flask run now and go ahead
and go to my website, it just says no. Today doesn't happen to be New
Year's, so it's telling me no. If, on the other hand, I wanted to
simulate it and pretend that it is New Year's, let me just-- after I set
new year equal to the month is one and the day is one-- let me just override it. New year is going to be true. Let's just tell our web application
that it is New Year's today, even though it's not, and refresh the page. And what happens now? Then it says yes, happy new year. So the HTML content is
able to change depending upon the values of the variables. And if I look at the page
source of this web page, it just says body and then this H1
tag it says yes, happy new year. There's no trace of that no that
was inside of my index.html template because the template gets processed
and rendered first on the web server. The server looks through
the templates, figures out the conditions, figures out what html
code to include, what not to include, what to plug in to particular
spots, and then takes that result and gives that result back to the user. So the user never sees
the original contents of the template with all the
different possible branches and different possible options
that could theoretically exist. And so using that code, we were
able to conditionally determine what to display on the HTML page. Questions about any of
that we've seen so far in terms of Python or Jinja or flask? Yeah? AUDIENCE: What's the reason why you put
the ir else on the index.html and not in the Python? BRIAN YU: Great question. So why did I put the if else
inside the index.html instead of inside of the Python code? I certainly could have put
it inside the Python code. So I could have said something
like, I want my text to be yes, if it's New Year's, else if it's
not New Year's, no for example. I could have done something like this
and then just passed in the text. But as we start to deal with
more complicated websites where I might want
entire sections of HTML to appear depending upon
the value of some variable, the conditioning inside of the template
will become very, very helpful. You can imagine if this
were a much longer thing that I wanted to display if it were
New Years, like if it were New Years, I wanted balloons to
appear on the screen. I might have a lot of
code that's necessary in order to make those balloons appear. And it would be infeasible to put all of
that inside of the Python file itself. And so the conditions just offer a
way of changing the template such that all of the template code
is really inside the file. And then just based on the
settings of particular variables, I decide how I particularly
want to configure that HTML file for my
particular use case for this particular user
on a particular day. Yeah? AUDIENCE: [INAUDIBLE]? BRIAN YU: Great question. Do you need to install Jinja2 in
order to make any of this work? What you will need to do
is you'll need to install flask, which is the micro framework
that we've been using in order to generate these web applications. And when you install flask,
Jinja2 come along with it. So as you install flask, Jinja2
will be first installed such that you can use flask and take
advantage of all Jinja2 features that come along with it. Good question. Yeah? AUDIENCE: So with flask, we don't
use Javascript anymore at all? BRIAN YU: Good question. Do we use JavaScript? We can still use JavaScript. We haven't quite gotten there. But it's totally fine to use JavaScript
inside of the client side of the web application, inside of the HTML
file that the user ultimately sees. And that works pretty
well with flask too. You can combine the two together. Yeah? AUDIENCE: Is it conventional
to call it-- give it the suffix html in this Jinja file? BRIAN YU: Yes. The question was, what is the
convention for what to call the files? Generally speaking, our
template files are HTML, even though they have
Jinja added to them. And so by convention,
we'll still call them HTML files, since their
contents are predominately HTML. Good questions. So that was an example of
conditions inside of Jinja. But like Python, Jinja has a
bunch of additional features too. In addition to conditions, we
also have loops, for example. So how might we go about having some
loops inside of our flask applications? Let's take a look at an example of that. So inside of application.py,
I've here, in the default route, just specified a bunch of names,
Alice and Bob and Charlie. And on line eight I'm returning
rendering the template index.html, passing in that whole list of
names into my index.html template. And presumably in my
index.html template, I want to display all of
those names on the web page. So what do I do inside of index.html? Well, here's what's going on
inside the body of this page. I have a URL, which is in
just an unordered list. And now I have this curly brace
percent sign syntax again. We used that same
syntax when we introduce a if statement or a condition in Jinja. We'll do the same thing when we want
to add a for loop into our template. And we have for name in names. Same exact syntax as we
would have used in Python. And that means we're going to
loop over that list of names. And for each name, here is
the code you want to add. We want to add an li,
a list item, where we plug in using that double curly
brace syntax the individual name. And so I've effectively said
create an unordered list. And inside of that
unordered list, for each one of the names in my list of names,
add a li tag, inside of which is the actual name that I wanted. So if I now run this application
and press Return, what I get is names big headline
and then one list item for each one of those individual names. I didn't need to, on three separate
occasions, type li tag name slash li. I only needed to do that once. And because I have it inside
of this loop that looping over this list of names, then it's
going to dynamically generate the list items as I need them. And so if I were to add
a fourth name, like, I were to add David to my list
of names and refresh it, it adds another list item
to that automatically, updating HTML such that if I actually
look at the page source what's happened is it's created this
unordered list and then it's created one list item for each one
of those items that was originally inside of my original list. Questions about loops or
how that was able to work? We'll take a look at a couple
of other features of flask that are ultimately going
to be helpful as you start to build a web applications
using this type of technology. One thing that might
immediately be helpful is figuring out how you link
to different parts of your web application. You might have one route that links
to another route and that route needs to link back to the
original route, for example. How would you go about doing that? Let's take a look at some URLs. So inside of application.py
I have two things going on. I have a default route that just renders
an index.html page up and a slash more route that is going to render
a more.html page presumably for more information, more text, an
additional page worth of information. Nothing too crazy going on here,
just two routes, each of which renders a different HTML template. Let's take a look at
those HTML templates. Here is index.html. I have a heading that says first page. I have a paragraph of text. And then down here is where
the interesting stuff happens. Here is where I will
link to the other route. So I have here in a href
tag which we've used before in order to link to a different page. But in this case, I'm using
the special syntax curly brace curly brace and
then a special function in Jinja URL for, and then the name of
a Python function, in this case more. And so what I've done
here is said I want to link to whatever the
URLs for the more function, in particular, this
is the more function, the one I've given the
name more to, and I want to just link to whatever route
will take me to that function such that later on down the road
I might change that route. That route's name might change such that
it appears as different to the user. But this code doesn't have to
change, because all this code is saying is figure out what the URL is
for the more function and link there. And I'm using the double
curly braces to mean substitute that URL in place in
between the quotation marks here. Likewise in more.html I have basically
the exact same thing going on. I have a heading. This the second page, a paragraph
worth of text, and then actual saying, here's where I want to link to. Go back to whatever route had the
index name of the function for it. And so what happens if I
now run this application? I have my first page that has
a whole paragraph of text. And when I click See More, that
takes me to the second page. And Go Back takes me
back to the first page. And so this URL for syntax can be
used in Jinja or in my Python code itself to just say get the URL that
will take me to a particular function. And so that's a helpful way of
often linking to different files. And one thing you may be
noticing at this point in time, is that there is a lot of similarity
between my index.html file, that first page that I showed
you, and this more.html file, the second page that I showed you. In particular, they both
have the same HTML head, title as my website on both of them. They both have this H1 at the
beginning of the body that has some title for the page. They both have this paragraph. And so ultimately these
pages are very, very similar. And what we might like
to do is find a way to factor out those
commonalities such that I don't need to copy paste my index.html
page create a more.html page. I can just take whatever is
common to both of those pages and use it as a layout, as a template
to base these other pages on, and then modify those new pages
slightly in order to make the necessary adjustments that I need. That way, instead of
writing the same code twice, I can just write the basic
template from my web site once and fill in the blanks
with whatever additional details that I have. So let's take a look at that in flask. It's a feature called
template inheritance. So we'll go ahead and
look at inheritance. And application.py is identical. The slash route just
takes me to index.html. The slash more route
renders the more.html. But here's what's different. Inside of my templates
directory I now have three files, an index.html
file, a more.html file, but also a layout.html file. And let's look at that
layout.html first. So what's going on
inside of layout.html? Well, I've defined the basic
layout for one of the web pages that I might want to have, either
an index. html or in more.html. I have my HTML header. The title is my web site. That's the same for both. They both got a body. They both got an H1 that's
going to be the heading. But here I've added some special syntax,
block heading and then end block. What I've done here is defined a
variable section of my HTML template saying that a block of HTML content
could go here called heading. And this is where that heading block
should go, in between the H1 tags. And then after the H1 tags I have
another block called the body block. And the heading and body are
just names that I picked. They could've been called anything. But I'm saying I have
whatever I call the body block should be inserted right here into
the body of my layout.html template. So now as you can begin to imagine, my
index.html file and my more.html file don't need to redefine this entire
structure of what the HTML web page looks like. All they would need to
do is simply say here is what belongs inside of
the heading and here's what belongs inside of the body. And aside from that, just use
this basic layout as my template that going to inherit from when I
define what index.html and more.html ultimately look like. So what does index.html look like? Well, here's that code. On line one up here, I've
said extends layout.html. In other words, index.html is
going to be based on layout.html. So let's just copy that HTML
and use that as the template that I'm going to use. But I want to make a couple
key changes or additions. Inside of block heading this is what I
want to be contained inside of heading. I just want it to say first page. And then end block to say that's
the end of that heading section. And then inside of the
body block, here is what belongs in the body of the website,
this paragraph worth of text and then this link to going onto the more page. And that's what's contained
inside of the body. And so if you remember
back in layout.html, we had that space for
where the heading should go and that space for where
the body should go. And all that's going
to happen now is when I render index.html it's going
to look to layout.html and try to plug in this heading content into
where that heading block was and plug in this body content into
where the body of that layout was, and render the resulting HTML page. And so likewise, inside of
more.html I have the block heading that defines a slightly
different heading block and a slightly different body block. But ultimately, they are both
extending that layout.html default file that is where I am defining the
general structure of my HTML page. So if I run this web server
now and refresh that, it looks exactly the same. First page, see more takes
me to the second page. But now notice that any change
that I make in the layout is going to then influence
both index.html and more.html. If I add an extra line like, welcome
to my layout file, now suddenly both on the first page
and on the second page they both have this
additional welcome line. Because this is information that was
drawn from my layout.html template from which both index.html
and more.html are extended. They're getting their
content from layout and basing themselves
off of layout.html. And so as a result of all of that, we're
able to get this template inheritance whereby I can make a change
once and see the impact of that all across the rest of
the files that are also inheriting from that same layout. So in project 0 as you
went about designing a whole bunch of different HTML pages
that were all about some central theme. And you may have noticed that
there was a lot of repetition where you would need to copy
different content from one page onto a second page and a
third page and a fourth page. This offers a solution
to that problem, whereby you can define a simple layout that
is both shared in common amongst all of your pages, and then
on each individual page, just define the sections that are
different from one page to another. And this is often a better
design for your websites. And you can see how flask
gives us the ability to leverage this template
inheritance in order to create these websites that just
have certain parts of each HTML page that differ from one page to the next. Questions about template
inheritance or how we were able to base HTML
files off of other layouts? Let's take a look at a
couple of other things. Let's take a look at forms now. So if you remember back
to our HTML lecture, we talked about how you
can go about creating HTML forms just by using form tags. But up until now, those forms
didn't really do anything. You would submit the form
and nothing would happen. Now that we have a back end server,
a Python flask server that's running and listening
to requests, we can begin to take the results of those forms
and do something interesting with them. So let's look at forms and
look at application.py. So first thing to notice is
that our index function is just going to be returning index.html, very
similar to all of the rest of the web pages we've done. Don't worry about this
second function for now. But let's just look at index.html
and see what it's doing. So index.html is extending
layout.html just like it did before. Our heading is going to say first page. And here's what's in the
body of this web page. It's going to be a form,
and in particular, this form is going to have an action. The action is when I submit this
form, who should be notified or where should I be
submitting this form to? And in particular, it's going to be
the URL for a function called hello which we saw back an
application.py, but we'll take another look at that in a moment. And we're saying the method for
this request is going to be post. So HTTP request, which
we talked about before is the process by which your browser
makes a request to a web server to get information, these requests can
come in a number of different methods where by default, if I go to
google.com and press Return, I am making a GET request. I'm asking to get
information from a web page. And so the default request
method is just yet. And so far in all the flask
applications we've been building, we've been using that default GET
request method for all of our routes. But this time for our form
when we're submitting data to the server, oftentimes that will
use a slightly different request method called post. And so here we're saying
when I submit data to hello, use the request method post
to mean I want to submit data as a form to the web server. What data am I submitting? Well, I have an input field whose
type is text, whose name is name. That name will now become relevant. I've given a name to the input field,
in this case it's just called name. And the placeholder just
says enter your name. And then I've added a button
that will submit this form. So this is a form much
like the ones we've already seen before, the only
difference is that now we've enclosed it inside of a Jinja template
instead of just a normal HTML file. Now what's going on in application.py? What's happening? On line 9 here is my slash hello route. And in particular, I'm
telling this route here is the request method you should accept. People are going to be submitting data
to this route via the post method. They're going to be submitting data
via post to this hello function. So what should this hello function do? Someone types in their name into the
form, they press the Submission button. This function gets called. What happens? Well, up here on line 1, from flask
I've imported flask and render template just as before, but I've also
imported this thing called request that is going to represent
whatever request the user has made to my web server. And so now here on line 11 I'm
defining a new variable called name. And I'm saying name
should be equal to what? I'm going to take that
request that the user made. Access the form, request.form. And let's get whatever part
of the form was called name. So if you remember back in the form
itself, in the HTML code, on the input I gave it a name attribute which was
equal to in quotation marks "name." That's what this is, the name of the
input field that I'm trying to access. And I'm going to access that
input field and just call it name. And what am I going to do
with that variable name? Well, I'm going to
render a template called hello.html, passing in that name
as a variable into the template. Just like we were passing names
into the template before in order to say hello to different people, this
is going to do much the same thing. But instead of getting
the name from the URL, we're going to get the name from the
form that the user just filled out. So how is that going to work? Let's look at hello.html. Inside of hello.html the heading
is just going to be the word hello. And the body of the website is
hello, and then in those double curly braces to mean plug in a value here. I'm plugging in the
value name, because I want to say hello to whoever the name
is, but I don't yet know who it is. And again, both of these files are
extending that basic layout.html file that defines the general
structure for a web page. So what happens if I now
run this web application? I go to the web page. This is the first page. Here is the form. I can enter my name here. So if I type my name
and press Submit, I'm now submitting that form to
the slash hello route via post. I'm sending the data within
the form, in this case my name, to the slash hello route. And what that's going to do is run
the code inside of my hello function. And the result of that is that
it's going to say hello Brian. Again, why did that happen? It's because in index.html, the action,
where the form should be submitted to, is the hello function. Then inside of application.py,
here is the hello function. What happens inside of it? I first get the name from the
form, request.form.getname. Save it in a variable called name. And then render the template
hello.html, passing that name variable in as a value that I want to then
display in the resulting template. And so now I've created a
form just like I did before, but I'm doing something with the form. I'm taking the data that the
user passed into the form, and using it to generate a
dynamic HTML page just for them. Questions about forms or
how we made that happen? Yeah? AUDIENCE: What happens if you
just typed in the URL dash hello? BRIAN YU: Great question. Question is what happens if,
instead of submitting the form, which goes to slash hello? I were to instead, just go to
this URL slash hello, and just press Return there? So recall that when you type
in a URL and just press Return, that is a get request. The default request
method in HTTP is just trying to get the
contents of a web page. And here, I'm just going to ask
to get the contents of hello. I'm not submitting any
form data to hello. What I get is method not allowed. This method is not allowed
for the requested URL. And why is that the case? What is it about these
four lines that caused me to get a method not allowed error? Any guesses? Yeah, it's this method equals
post part of the route that says the only request methods I should
accept is the request method post. If someone just tries to
get the page normally, then there should be some sort of error,
because that's not a supported request method. I could try to support both. I could say I want to support
both, just someone typing flash hello, and someone going to the regular
route and submitting the form via post. And to do that, I would just
say method equals GET and POST. I can have a list of different
requests methods that I allow. And here I'm saying the flash slow route
will accept both GET requests and POST requests. How do I tell them apart? Well, I can use this
request object again. I can say if request.method equals
GET, for instance, let's just return please submit the form instead, else,
if the request method isn't GET, which means the request method has to be
POST, then do the same thing as before. Get the name, and then return
the hello.html template with the name filled in. Now if I go to slash hello, what I
get is please submit the form instead. Because I tried to
access this page via GET. But instead, if I just go to the
default page and type in my name, and submit that form,
then I get the hello. So flask is able to detect
what the request method is. And if the request method is GET, do one
thing, if the request method is POST, do something else. And so flask can
differentiate between just trying to access the page versus trying
to actually submit data to that page. Other questions about
that or other things? We'll take a look at one other example. So, so far, our web applications
haven't been able to-- question? Yeah? AUDIENCE: So if the form had a GET
method specified with [INAUDIBLE],, would the request form get-- BRIAN YU: So the question is if the
form, instead of being method POST, were method GET, and I tried to
submit by the GET method instead? Well, in this case, it's going to get
caught in request.method equals GET. So what will happen is that
if I go to the default route and try to type in my name and
submit it, I'm going to get please submit the form instead,
because it was a GET request. But hypothetically, you could also
have data submitted via GET instead. When you submit data via GET,
that data gets put into the URL. So notice that what changed here
is that I requested slash hello and then question mark name
equals Brian, where that basically means that I've submitted
form data via GET, and that data is all put into the URL. And so the result of
that is that you can change what's in the URL to change
what the specific request is. This is also not a good idea if
there's any sensitive information that you want to submit via a form. If someone's typing in their password
for example, to log in to your website, you don't want that form to be
submitted via GET, because now in the URL, that appears in
their URL history for example. Their password's just going to
be plainly visible in the text. And so oftentimes, for more
secure form submissions you'll want to use POST
requests instead of GET. But you could also
submit data via GET too. I'm just going to change
that back to POST. Good question, though. So thus far, our web
applications haven't really been able to store information. We've been able to use
web applications in order to take information and
do something with it, whether it was the
name that someone typed into the URL to say hello to them. Or whether it was a form
that users are filling out that they fill out the form,
press Submit, and then the website says hello to them. But now we'd like to
create a website that is able to store information,
retain information, and use that information later, for example. And that's where we can start to
introduce the concept of sessions. And so sessions in flask
or in web programming, more generally is the idea that when
you log in to the web site, you have access to some session that
is data specific to your user account. So I log into Google.com. And I see that I'm logged
into my Google account and have access to my Google
documents, for instance. Whereas you might log into Google
and see an entirely different thing, depending upon how you
are logged in as well. So how can we begin to
make use of those sessions? Let's take a look at a example. So this doesn't yet
actually use sessions. But it's an example of us
being able to store data. So let's say I wanted to create a
note taking application, for example. So how might I create a
note taking application where I want to be able to
store different types of notes that people are typing in order
to record notes and save notes on this website? So what do I have going on? On line 10 I've defined
this notes variable to so far, just be an empty list. It's just going to be
an empty list of notes that is going to store the notes that
I'm eventually going to be saving. Then I have a default index route,
where inside of this index route, I have a couple of things going on. If the request method is POST,
which we haven't yet seen. But if I were to submit data
to the index form-- and I'm not sure how I would do that just yet. But we'll see in a moment. Then what do I want to do? I want to access whatever note
I wanted to add presumably, because I just tried to add a note. And then notes.append note it's my
way of saying take this list of notes and add a new thing to the list. In particular, add this
new note to that list. So that's what happens if
the request method is POST. If I submit data to this index
function, then what I should do is add a new note to my list of notes. And then otherwise, if I didn't
submit any data, or even if I did, just at the end, return this
index.html passing in my list of notes. What's happening inside of index.html? Well, what I have here is a for note in
note, print out each individual note. And all of that is stored
inside of an unordered list where have an ordered list of notes. So what that's going to do, is
much like we saw that list of names that we could then use to
generate one name at a time in order to display a
list of names, we can display a list of notes that
will display one note at a time on each item inside an unordered list. Then lower down on the
page, I have a form. And this form is presumably
where I could add a new note into my notepad web application. This form is going to have an action
of going to the index page, that's where I want it to go. The method is POST, just like before. And this is very similar
to the form we just saw. It's got an input field whose
name is note this time, and whose place holder is enter your
note here, and then a button to add a note to my list of notes. So we'll take a look at
all that in just a moment. But let's take a look at how the
web application actually works. And then take a closer
look at what's actually going on inside of flask
and the application.py to make all of that possible. So I'll go ahead and flask run this. I'll go to the default route. And what I see here is just a heading
that says notes and then this form. Enter note here, and then add note. So what happens if I type hello
as a note and click Add Note? Well, that will add hello
as just a note that I've now recorded inside of this list. And if I add hello
again, as another note? It adds that too. So how is that working? Let's take another look
back at index.html. When I add a note, what's happening? I'm submitting this form. And I'm submitting this form
back to the index function or whatever URL maps to the index
function, which in this case is just slash. And I'm submitting that data via POST. What's then happening
inside of application.py? Well, I'm maintaining this
list of notes right here, just an empty list to
start out with, which is why I have no notes to begin with. But then in the index function,
if the request method was POST, if I did try and add a note,
then what's going to happen? I'm going to set note
equal to whatever is the note parameter of that
form, whatever thing in the form had a name called note. And then I'm going to append to
my already existing list of notes, that new note. And then only at the
end of all of that am I going to render the
template index.html, passing in that whole list of notes. And what that's going
to do is ultimately save all of those notes as a variable
that is accessible to my entire web application. And so what's going to happen then
is that if I type in a third note and add the note,
that's going to appear. And if, for example, I were to close
this web page, but open it up later and type in the URL again,
those notes are still there. My web server is saving the
value of all those notes as a variable inside of the web server. And as a result, I can see all those
notes even if I close the web page and open it up again later. Those notes are still retained. If on the other hand, I were to ever
for some reason shut down my web server. And you can quit flask by
pressing Control-C, for example, and start up again by
typing flask run, now I've restarted the whole web server. It's completely
restarted application.py. And when I refresh this page,
now my notes are gone again. And so I've lost access to all of
them because the server was shut down. And when it restarted,
everything was reset. And so next week we'll begin
to look at database design, and how we can resolve this
problem by trying to figure out how do we take data that the user
submitted and store it somewhere longer term, somewhere that even
if the server goes down and come back later or even if we're
accessing it from somewhere else, we can still get back at that same data. And so that's where using and
taking advantage of databases will become quite helpful. But one last thing to note
about this particular website is that this notes
variable is what we call a global variable, accessible
across the entire application, which means that if I'm using this web
application and taking notes with it, and potentially, someone
else also wants to use my web application on the
internet, presumably, we don't want to be working with
the same note pad, so to speak. I want to be able to take my own notes
without seeing someone else's notes. And I don't want someone else
to be able to see my notes. But if I just have the
single notes variable that's shared across the
entire web server, then even if someone else
tries to visit my website, they're going to see all of
that entire same set of notes. And so that's where
the concept of sessions begins to come in, that
when I log into my web site, I want to see my list of notes. And when someone else logs
into the same web site, they want to see their list of
notes without those lists of notes ever overlapping, so to speak. And so how do we make that happen? What changes do we need to make
in order to allow for that? Well, what we're going to do
is from flask, import session. And that gives us access to a variable
called session, which we can then use them in order to keep variables
and values that are specific to a particular user, such that
I have my own session that's all data specific to my
interactions with the website, and someone else has their own session
that has all of the data specific to their interactions
with their website. And then on line two I'm importing
a special additional extension to flask called flask session. This just give us a little bit more
control over sessions, in particular, it lets us store session "server
side" such that on our server we're storing all the data
about the sessions which gives us just a little more control
over how the sessions are managed. But not to worry too much about that. What's important is that I now
have access to this variable called session which is unique to me, such that
now if I, instead of saying that notes is going to be this global variable
that everyone has access to, I can treat the session as a
dictionary that is specific to me. So I can say session square bracket
notes is equal to the empty list, to mean I want my particular session
to have an empty list of notes, for example. And then, instead of notes.appendnote,
I can say sessionnotes.append notes. Rather than append this new note to
the entire global variable representing all of the notes, I only
want to append the note to the notes specific to
my particular session, to my interaction with this page. So what's going to happen
here now if I try and run this web application is I can try and
type my first note and nothing happens. AUDIENCE: You missed the
last line, [INAUDIBLE] BRIAN YU: Oh, wonderful. Thank you. So notes should be
session notes instead. And if I run this again, it say notes. I type in my first note. I add the note. Now the first note appears. What happens if I try
adding a second note? What's going to happen? It overwrote the first note. First note went away. Why did that happen? Any ideas? AUDIENCE: You're resetting
the session notes each time. BRIAN YU: Exactly. On line 14 here, I've
reset session notes. So I needed to give session
notes some initial value in order to say if session notes doesn't
exist, it needs to have something. But if I have it here in
the index function, then every single time I
submit new data to index, it's going to clear out
all of my own old notes. And that's clearly not what I want. So maybe I want something like
this, if session.getnotesisnone. In other words, if I try and
get the notes from the session and it doesn't exist, then I want
session notes to be an empty list. In other words, if I didn't
have any notes already, let's initialize notes
to be an empty list. That way it exists, at least. But otherwise, let's just
keep it as what it is. So now it's a second note. Now if I type third note and add
a note, it adds the third note just like we would expect it to. And so the advantage here is that now I
have multiple different sessions going on, such that this particular user is
independent of other particular users. We don't have one shared notes variable
across all of the different users. And if you were to
eventually go to my website if I hosted somewhere on the internet,
that will have its own set of notes, and so on and so forth, so
that everyone's user accounts can be kept separate. And so questions about sessions, or how
we might go about storing data inside of our flask applications? AUDIENCE: So if you close the
browser now, you lose your notes? BRIAN YU: If I close the browser
now and then go back to it, I get to keep my notes. Because it's still stored
inside of the session. AUDIENCE: It knows your session? BRIAN YU: It knows my session, yeah. It is able to identify
my particular web browser request by a cookie, just a value that's
being stored inside the web browser. And so the next time that I make
another request to that web page, it recognizes me and says oh,
I know exactly who you are. Here are the notes that
I have saved for you. And it can display my notes
back to me that way as well. And so you can imagine this
being useful for websites where you have to log in and
see particular data that's very pertinent to you. Yeah? AUDIENCE: Just to be clear, so line
10 in your file is no longer needed. BRIAN YU: Line 10 in this
file is no longer needed because I no longer have a global
notes that is shared across everyone. I only have notes that are very
specific to a particular user's session. Good question. Yes? AUDIENCE: Is there any website
that describes all of this kind of [INAUDIBLE]? BRIAN YU: Is there a website
that describes all this? Yeah. So flask has great documentation. If you just go to
flask's web site, you'll see descriptions of basically
all of these features plus more in great detail, giving you
examples of different features of using the flask framework. So what we've seen so far is just a
taste of what flask is able to do. We've seen it able to build routes
for us, build templates for us. We've been able to add logic like loops
and conditions into flask templates as well. But it's got a whole lot
more features as well. And in particular, next week we'll
be diving into building databases and connecting databases
to flask, such that flask can better interact with data
that's provided by users, such that we can better manage user
accounts and manage relationships across different kinds of data. And all of that is coming next week. But for now, that's Python and flask. And we'll conclude here for today. Thank you all.