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.