1 00:00:00,000 --> 00:00:00,550 2 00:00:00,550 --> 00:00:03,220 BRIAN YU: Using HTML, CSS, and JavaScript, 3 00:00:03,220 --> 00:00:05,260 we were able to create web pages that users 4 00:00:05,260 --> 00:00:09,400 could view by serving them using HTTP server, a simple server that 5 00:00:09,400 --> 00:00:13,810 just listened to prefer requests and sent back those web pages as responses. 6 00:00:13,810 --> 00:00:17,800 But those responses were always what we might call static content. 7 00:00:17,800 --> 00:00:21,100 Every time HTTP server sent back an HTML page, 8 00:00:21,100 --> 00:00:25,330 the actual HTML content of the page app was always the same. 9 00:00:25,330 --> 00:00:27,760 But in practice, modern web applications are often 10 00:00:27,760 --> 00:00:30,880 sending back dynamic content, content that's changing. 11 00:00:30,880 --> 00:00:33,040 Social media sites like Facebook and Twitter 12 00:00:33,040 --> 00:00:36,610 are always sending back HTML that contains for the users their latest 13 00:00:36,610 --> 00:00:38,350 posts and their latest news feed. 14 00:00:38,350 --> 00:00:40,360 And news websites are always sending back 15 00:00:40,360 --> 00:00:44,390 HTML that contain the current day's news articles, for example. 16 00:00:44,390 --> 00:00:46,750 And so how do we create something like that? 17 00:00:46,750 --> 00:00:49,870 Well, to do that we're going to need to write our own web server, 18 00:00:49,870 --> 00:00:52,600 our own application that is listening for web requests 19 00:00:52,600 --> 00:00:56,800 and responding to them so that we can decide what HTML we want to send, 20 00:00:56,800 --> 00:00:59,560 and we can send dynamically generated HTML 21 00:00:59,560 --> 00:01:03,310 based on the data that's currently stored inside of our web application. 22 00:01:03,310 --> 00:01:05,790 To do that here, we're going to use Flask, 23 00:01:05,790 --> 00:01:09,520 a Python based framework that makes it very easy to set up and create a web 24 00:01:09,520 --> 00:01:13,510 server that's going to listen for requests and respond to those requests 25 00:01:13,510 --> 00:01:14,780 as well. 26 00:01:14,780 --> 00:01:19,500 So let's go ahead and create our very first Flask web application. 27 00:01:19,500 --> 00:01:23,160 I'll go into CS50 IDE, and I'll create a new folder 28 00:01:23,160 --> 00:01:25,800 where I'm going to store all the files for this web application 29 00:01:25,800 --> 00:01:27,020 that I'm about to create. 30 00:01:27,020 --> 00:01:28,800 And I'll call the folder Hello, which will 31 00:01:28,800 --> 00:01:31,170 be the name of this particular application. 32 00:01:31,170 --> 00:01:35,040 And inside of Hello, I'll create a new file 33 00:01:35,040 --> 00:01:38,160 that I'm going to call application.py. 34 00:01:38,160 --> 00:01:40,800 And this is just a Python convention and Flask 35 00:01:40,800 --> 00:01:43,440 that when you have a Flask application, it is often served out 36 00:01:43,440 --> 00:01:46,410 of a file called application.py. 37 00:01:46,410 --> 00:01:48,942 What am I going to put inside of application.py? 38 00:01:48,942 --> 00:01:52,600 Well, the first thing I'll need to do is import the Flask module. 39 00:01:52,600 --> 00:01:56,740 So from Flask, I'm going to import Flask. 40 00:01:56,740 --> 00:01:58,840 Next, I'm going to create a variable that's going 41 00:01:58,840 --> 00:02:01,150 to represent my Flask application. 42 00:02:01,150 --> 00:02:06,640 So I'll say app equals Flask, and then __name just means that I'm going to be 43 00:02:06,640 --> 00:02:11,330 serving this flask application from this file that I'm writing right now. 44 00:02:11,330 --> 00:02:15,890 And now what I'm going to include in application.py are routes. 45 00:02:15,890 --> 00:02:19,340 And routes are just what you might type at the end of a URL 46 00:02:19,340 --> 00:02:21,740 in order to decide what page you want to visit. 47 00:02:21,740 --> 00:02:26,300 So on Google, for instance, you might be visiting /search or /settings or /maps, 48 00:02:26,300 --> 00:02:28,820 for example, to get to various different pages. 49 00:02:28,820 --> 00:02:31,550 Likewise, our web application can respond 50 00:02:31,550 --> 00:02:34,790 based on what route the user is trying to access. 51 00:02:34,790 --> 00:02:41,162 So we'll go ahead and say at app.route and then slash, where slash is here 52 00:02:41,162 --> 00:02:42,620 just going to be the default route. 53 00:02:42,620 --> 00:02:46,350 When you just visit the web page, this is the route that's going to run. 54 00:02:46,350 --> 00:02:48,470 And every route in Flask is associated with a. 55 00:02:48,470 --> 00:02:52,560 Function I'll go ahead and call this function index. 56 00:02:52,560 --> 00:02:58,870 And I'm going to return from this function hello world. 57 00:02:58,870 --> 00:02:59,800 And that's it. 58 00:02:59,800 --> 00:03:01,720 With just seven lines of code, I've now been 59 00:03:01,720 --> 00:03:04,210 able to write a Flask web application. 60 00:03:04,210 --> 00:03:06,520 And the gist of the idea is that line five, 61 00:03:06,520 --> 00:03:10,870 I'm saying, when you go to the slash route on this web application, 62 00:03:10,870 --> 00:03:13,125 you should call this function on line six, index, 63 00:03:13,125 --> 00:03:15,250 though it could have been called anything you want. 64 00:03:15,250 --> 00:03:16,820 And what does the function do? 65 00:03:16,820 --> 00:03:20,980 Well, it's going to return the content that should be responded to the user. 66 00:03:20,980 --> 00:03:23,270 And so in this case, when the user visits slash, 67 00:03:23,270 --> 00:03:27,380 I would like to send the message hello world to the user. 68 00:03:27,380 --> 00:03:29,590 How do I now run this web application? 69 00:03:29,590 --> 00:03:33,670 Well, inside my terminal I'll CD into my Hello directory 70 00:03:33,670 --> 00:03:35,380 to go into the Hello directory. 71 00:03:35,380 --> 00:03:37,810 And now to run my Flask web application, I 72 00:03:37,810 --> 00:03:43,630 can just type Flask space run to run this Flask web application. 73 00:03:43,630 --> 00:03:45,940 It's running on this particular URL. 74 00:03:45,940 --> 00:03:50,500 So if I click on that and go ahead and click Open, what I'll get now 75 00:03:50,500 --> 00:03:55,550 is a web page that here just displays the words hello world. 76 00:03:55,550 --> 00:03:56,560 So that was it. 77 00:03:56,560 --> 00:03:59,400 When the user visited slash on the web application, 78 00:03:59,400 --> 00:04:02,050 the index function was called inside of Flask, 79 00:04:02,050 --> 00:04:04,160 and the index function returned hello world, 80 00:04:04,160 --> 00:04:06,910 and so that's why what the user saw when they went to the web page 81 00:04:06,910 --> 00:04:08,745 were the words hello world. 82 00:04:08,745 --> 00:04:11,620 Let's make our web application a little bit more interesting, though, 83 00:04:11,620 --> 00:04:15,140 and add another route to the web application. 84 00:04:15,140 --> 00:04:18,329 So here I'll add another route. 85 00:04:18,329 --> 00:04:19,470 App.route. 86 00:04:19,470 --> 00:04:24,120 This time, instead of just slash, which is the default route, I'll do /goodbye, 87 00:04:24,120 --> 00:04:25,450 for example. 88 00:04:25,450 --> 00:04:28,230 What should happen when the user visits /goodbye? 89 00:04:28,230 --> 00:04:31,710 Well, here we'll say we're going to call another function that I'll call bye. 90 00:04:31,710 --> 00:04:33,780 But again, you could call it anything. 91 00:04:33,780 --> 00:04:40,010 And the bye function is just going to return goodbye exclamation point. 92 00:04:40,010 --> 00:04:41,630 So now I have two routes. 93 00:04:41,630 --> 00:04:45,560 A default route accessible by just going to slash on my web page 94 00:04:45,560 --> 00:04:47,970 and getting hello world as the response. 95 00:04:47,970 --> 00:04:52,380 And then if I go to /goodbye on my web application, I call the bye function, 96 00:04:52,380 --> 00:04:54,740 which returns the word goodbye. 97 00:04:54,740 --> 00:04:56,000 So we can try it. 98 00:04:56,000 --> 00:04:59,030 If I go back to my web application and just refresh, 99 00:04:59,030 --> 00:05:00,660 I'm still on the default route. 100 00:05:00,660 --> 00:05:03,950 So what I see are still the words hello world. 101 00:05:03,950 --> 00:05:07,360 But if I go up now to the URL bar and instead of going to the default route 102 00:05:07,360 --> 00:05:13,160 of just slash or nothing there, if I instead type /goodbye, for example, 103 00:05:13,160 --> 00:05:15,350 what I now see is the word goodbye. 104 00:05:15,350 --> 00:05:18,500 That was what was located when I went to the /goodbye route. 105 00:05:18,500 --> 00:05:21,830 It called the bye function, and that returned this content 106 00:05:21,830 --> 00:05:24,640 that I now see on this web page. 107 00:05:24,640 --> 00:05:28,790 And it turns out that what I return can be any arbitrary HTML that I want. 108 00:05:28,790 --> 00:05:31,250 Instead of just returning hello world, for example, 109 00:05:31,250 --> 00:05:35,270 you might imagine surrounding it in H1 tags 110 00:05:35,270 --> 00:05:39,260 so that it displays hello world as a bigger, bolder heading. 111 00:05:39,260 --> 00:05:43,710 So if I go back now to just the slash route, the default route on my web 112 00:05:43,710 --> 00:05:47,160 application, I now see hello world in bigger, bolder letters 113 00:05:47,160 --> 00:05:50,710 as a big heading at the top of this particular web page. 114 00:05:50,710 --> 00:05:53,340 But as you might imagine, the HTML I'm returning 115 00:05:53,340 --> 00:05:56,700 might be a little more complex than just one big heading at the top. 116 00:05:56,700 --> 00:05:59,880 I might have beneath that more information, other paragraphs, 117 00:05:59,880 --> 00:06:02,560 other images, other HTML content as well. 118 00:06:02,560 --> 00:06:05,190 And if I had to type all of the HTML content 119 00:06:05,190 --> 00:06:08,400 that I wanted to return when the user visits the slash route 120 00:06:08,400 --> 00:06:11,310 inside of this string right here, that's going to eventually start 121 00:06:11,310 --> 00:06:13,680 to get pretty tedious and pretty messy. 122 00:06:13,680 --> 00:06:17,070 And so what Flask allows us to do is separate some of this information 123 00:06:17,070 --> 00:06:22,110 out into other files, in particular into what are called the template files. 124 00:06:22,110 --> 00:06:23,380 How does this work? 125 00:06:23,380 --> 00:06:25,920 Well, inside of the Hello folder, I'll go ahead 126 00:06:25,920 --> 00:06:29,730 and create a new folder that needs to be called Templates. 127 00:06:29,730 --> 00:06:33,750 And this is where Flask is going to look for template files. 128 00:06:33,750 --> 00:06:39,600 Inside of Templates, I'll create a new file called index.html. 129 00:06:39,600 --> 00:06:43,970 And inside of index.html, I'll just include some HTML content. 130 00:06:43,970 --> 00:06:48,330 Doc type HTML, HTML, inside of which is the header 131 00:06:48,330 --> 00:06:50,940 section of the title that says hello and then 132 00:06:50,940 --> 00:06:55,150 a body section that says hello world. 133 00:06:55,150 --> 00:06:58,230 All right, so now inside of application.py, 134 00:06:58,230 --> 00:07:03,390 rather than returning this string of just H1 hello world end H1, 135 00:07:03,390 --> 00:07:05,610 I can now return a template. 136 00:07:05,610 --> 00:07:07,920 In order to do that up at the top from Flask, 137 00:07:07,920 --> 00:07:10,230 in addition to just importing the name Flask, 138 00:07:10,230 --> 00:07:14,010 I'll also need to import a Flask specific function called 139 00:07:14,010 --> 00:07:16,000 render template. 140 00:07:16,000 --> 00:07:18,850 And I'm going to call that from the index function. 141 00:07:18,850 --> 00:07:21,790 I'm going to return render template. 142 00:07:21,790 --> 00:07:26,220 And the argument to the render template function is the name of the HTML file 143 00:07:26,220 --> 00:07:28,090 that I would like to render in this case. 144 00:07:28,090 --> 00:07:33,000 In this case, I want to render index.html. 145 00:07:33,000 --> 00:07:36,830 All right, so now when the user visits the slash route on my web page, 146 00:07:36,830 --> 00:07:38,840 it's going to run the index function. 147 00:07:38,840 --> 00:07:40,730 And what the index function is going to do 148 00:07:40,730 --> 00:07:45,210 is it's going to render a template that's called index.html. 149 00:07:45,210 --> 00:07:48,110 So if I go back to my web application, refresh the page, 150 00:07:48,110 --> 00:07:53,240 I now see this index.html file, which has a body of hello world 151 00:07:53,240 --> 00:07:57,190 and also has a title of hello, which I see at the very top. 152 00:07:57,190 --> 00:08:00,800 OK, so we've now been able to create a Flask web application that 153 00:08:00,800 --> 00:08:04,580 is able to handle routes and when a user visits a particular route, 154 00:08:04,580 --> 00:08:07,670 it's able to return to them some HTML content. 155 00:08:07,670 --> 00:08:09,830 But of course, this HTML content is still 156 00:08:09,830 --> 00:08:11,600 what we might call static content. 157 00:08:11,600 --> 00:08:14,730 It's always the same HTML all the time. 158 00:08:14,730 --> 00:08:17,780 So now let's leverage the fact that we've written this web application 159 00:08:17,780 --> 00:08:21,710 in Python, a programming language that allows for constructs like variables 160 00:08:21,710 --> 00:08:25,250 and loops and conditions, to be able to dynamically generate 161 00:08:25,250 --> 00:08:27,110 some more interesting content. 162 00:08:27,110 --> 00:08:28,850 So how might this work? 163 00:08:28,850 --> 00:08:31,490 Well, let's go back to application.py, where here you'll 164 00:08:31,490 --> 00:08:34,429 recall that when a user visits the slash route, 165 00:08:34,429 --> 00:08:39,390 we call the index function that returns a template called index.html. 166 00:08:39,390 --> 00:08:43,010 But it turns out that this render template function also has the ability 167 00:08:43,010 --> 00:08:46,190 to pass in variables to our HTML files. 168 00:08:46,190 --> 00:08:49,310 And previously, our HTML files haven't been able to deal with variables. 169 00:08:49,310 --> 00:08:52,040 They've just had static content and tags and elements 170 00:08:52,040 --> 00:08:54,360 and information within those elements. 171 00:08:54,360 --> 00:08:58,920 So here I might be able to pass the index.html some additional values 172 00:08:58,920 --> 00:09:03,300 of variables where I might same comma name equals, 173 00:09:03,300 --> 00:09:05,210 let's say, Emma in this case. 174 00:09:05,210 --> 00:09:09,590 Where here I'm going to give index.html access to a variable 175 00:09:09,590 --> 00:09:14,300 called name, which in this case is going to be equal to Emma. 176 00:09:14,300 --> 00:09:16,050 What can I then do with that? 177 00:09:16,050 --> 00:09:20,120 Well, inside of index.html, instead of saying hello world, 178 00:09:20,120 --> 00:09:22,520 I'd like to say hello to Emma. 179 00:09:22,520 --> 00:09:27,050 And I'd like to effectively plug in the value of the name variable 180 00:09:27,050 --> 00:09:29,790 right here in the body of my web page. 181 00:09:29,790 --> 00:09:35,210 To do that, what I'll use is a syntax of double curly braces, name, and then 182 00:09:35,210 --> 00:09:36,710 double curly braces. 183 00:09:36,710 --> 00:09:38,600 This syntax is technically a syntax called 184 00:09:38,600 --> 00:09:43,070 Jinja, which is the templating language that Flask uses in order to display 185 00:09:43,070 --> 00:09:45,080 information and render these templates. 186 00:09:45,080 --> 00:09:48,920 But here effectively all I've done is inside of application.py, 187 00:09:48,920 --> 00:09:53,810 I've said render the index.html file and give index.html 188 00:09:53,810 --> 00:09:59,200 this template, access to a variable called name which is equal to Emma. 189 00:09:59,200 --> 00:10:02,360 And inside of index.html, I'm now saying hello 190 00:10:02,360 --> 00:10:07,220 to whatever that name happens to be using double curly braces to say plug 191 00:10:07,220 --> 00:10:10,250 in the value of the name variable here. 192 00:10:10,250 --> 00:10:14,540 I'll go ahead and restart my Flask server by running Flask run. 193 00:10:14,540 --> 00:10:17,380 And if I go back and refresh the page, you'll 194 00:10:17,380 --> 00:10:19,900 notice that now my page says hello Emma. 195 00:10:19,900 --> 00:10:22,690 It took the value of the Python variable name 196 00:10:22,690 --> 00:10:27,700 and it substituted it in to my index.html template. 197 00:10:27,700 --> 00:10:31,030 So this gives us access to a lot of very powerful features. 198 00:10:31,030 --> 00:10:33,400 So one feature of Python, for example, is 199 00:10:33,400 --> 00:10:36,830 that Python has the ability to generate random numbers. 200 00:10:36,830 --> 00:10:42,950 So let's say that I wanted a variable number to be equal to a random number. 201 00:10:42,950 --> 00:10:46,540 So I'll first the top of my file import random, 202 00:10:46,540 --> 00:10:49,900 which is a Python module that allows me to generate random numbers. 203 00:10:49,900 --> 00:10:55,030 And I'll set number equal to random.randint 1 comma 10, 204 00:10:55,030 --> 00:10:58,930 which will generate a pseudo random number between 1 and 10 inclusive. 205 00:10:58,930 --> 00:11:03,440 So 1 or 2 or 3 or 4, 5, 6, 7, 8, 9, or 10 pseudo randomly. 206 00:11:03,440 --> 00:11:08,410 And now what I'd like to do is pass in this variable into index.html. 207 00:11:08,410 --> 00:11:09,920 How might I do that? 208 00:11:09,920 --> 00:11:11,980 Well, instead of the variable being called name, 209 00:11:11,980 --> 00:11:13,660 I'll go ahead and call it number. 210 00:11:13,660 --> 00:11:17,590 And it needs to be equal to, well, in this case, it's still called number. 211 00:11:17,590 --> 00:11:20,210 So number equals number, which is a little confusing. 212 00:11:20,210 --> 00:11:22,540 But to be clear, this number on the right hand 213 00:11:22,540 --> 00:11:27,340 side represents the Python value that I want to pass into the template, which 214 00:11:27,340 --> 00:11:29,470 used to be Emma the string, and in this case, 215 00:11:29,470 --> 00:11:33,940 is the variable number, which I defined here on line nine. 216 00:11:33,940 --> 00:11:38,210 The number here on the left side of the equal sign is the name of the variable 217 00:11:38,210 --> 00:11:41,935 that the template should have access to inside of index.html. 218 00:11:41,935 --> 00:11:44,810 And it just so happens that in this case, both the name of the Python 219 00:11:44,810 --> 00:11:48,410 variable and the name of the variable I want the template to have access to 220 00:11:48,410 --> 00:11:51,680 are both called number, but there will be situations where these two don't 221 00:11:51,680 --> 00:11:54,490 necessarily have the same name. 222 00:11:54,490 --> 00:11:58,630 So inside of index.html now, rather than say hello name, 223 00:11:58,630 --> 00:12:03,670 I can say something like your random number is and then in double curly 224 00:12:03,670 --> 00:12:08,050 braces number, providing whatever pseudo random number was 225 00:12:08,050 --> 00:12:11,740 generated by my application.py file. 226 00:12:11,740 --> 00:12:14,350 I'll go ahead and reload my Flask server. 227 00:12:14,350 --> 00:12:16,630 I can press Control C to stop the web server 228 00:12:16,630 --> 00:12:19,310 and then Flask run again to run it again. 229 00:12:19,310 --> 00:12:22,765 And now if I refresh the page, your random number is 7. 230 00:12:22,765 --> 00:12:25,140 And if I refresh the page again, your random number is 1. 231 00:12:25,140 --> 00:12:27,010 If I refresh again, your random number is 8. 232 00:12:27,010 --> 00:12:30,700 Every time I run this application, it's generating a pseudo random number 233 00:12:30,700 --> 00:12:33,850 between 1 and 10 and then displaying that content to me 234 00:12:33,850 --> 00:12:35,700 inside of this HTML page. 235 00:12:35,700 --> 00:12:37,900 And if I view the source code of this HTML page 236 00:12:37,900 --> 00:12:41,560 by going to View, Developer, View Source, 237 00:12:41,560 --> 00:12:46,090 I can actually see here is the HTML that is getting returned back to me. 238 00:12:46,090 --> 00:12:49,660 Doc type HTML, HTML, this is all HTML that I wrote, 239 00:12:49,660 --> 00:12:52,100 but your random number is 8. 240 00:12:52,100 --> 00:12:54,550 When flask is running render template, it 241 00:12:54,550 --> 00:12:58,180 sees that I want it to substitute the value of the variable number here. 242 00:12:58,180 --> 00:12:59,980 So it does that substitution. 243 00:12:59,980 --> 00:13:02,560 And then the HTML that gets sent back to the user 244 00:13:02,560 --> 00:13:05,710 is just this new dynamically generated HTML. 245 00:13:05,710 --> 00:13:08,440 I didn't write the number 8 inside of the HTML file, 246 00:13:08,440 --> 00:13:10,930 but flask was able to render a template that 247 00:13:10,930 --> 00:13:14,800 inserted that value where I wanted it to be by specifying 248 00:13:14,800 --> 00:13:16,990 using those double curly braces where I wanted 249 00:13:16,990 --> 00:13:19,860 a placeholder for a particular value. 250 00:13:19,860 --> 00:13:22,250 And so there's a lot that you might be able to do here. 251 00:13:22,250 --> 00:13:24,640 So let's create a program, for example, a web 252 00:13:24,640 --> 00:13:29,600 application that simulates a coin flip, flipping heads or tails, for example. 253 00:13:29,600 --> 00:13:32,690 So how do we simulate a coin flip by flipping heads or tails? 254 00:13:32,690 --> 00:13:35,380 Well, inside of application.py, rather than generating 255 00:13:35,380 --> 00:13:38,150 a random number between 1 and 10 inclusive, 256 00:13:38,150 --> 00:13:42,200 let's just generate a random number between 0 and 1 inclusive. 257 00:13:42,200 --> 00:13:45,610 So 0 for tails, 1 for heads, maybe. 258 00:13:45,610 --> 00:13:49,690 And inside of index.html, if we left things exactly the same 259 00:13:49,690 --> 00:13:52,510 and I were to reload, what I'd see is your random number is 0 260 00:13:52,510 --> 00:13:55,180 or your random number is 0 or your random number is 1 261 00:13:55,180 --> 00:13:56,320 depending on the time. 262 00:13:56,320 --> 00:13:59,980 And so you can rerun this and get various different coin flips. 263 00:13:59,980 --> 00:14:04,640 But what I'd really like to be displayed is something like heads or tails. 264 00:14:04,640 --> 00:14:06,320 So how could I do that? 265 00:14:06,320 --> 00:14:09,560 Well, in addition to specifying variables inside 266 00:14:09,560 --> 00:14:14,400 of our Jinja templates, we can also have things like conditions and loops. 267 00:14:14,400 --> 00:14:17,080 So let's take a look at a condition now. 268 00:14:17,080 --> 00:14:21,320 So double curly braces is the syntax we use to insert the value of a variable 269 00:14:21,320 --> 00:14:22,370 somewhere. 270 00:14:22,370 --> 00:14:25,580 To have a condition, we're going to use curly brace percent 271 00:14:25,580 --> 00:14:27,930 sign as the syntax we use for that. 272 00:14:27,930 --> 00:14:30,620 And inside of the curly brace percent signs, 273 00:14:30,620 --> 00:14:33,620 it's going to be syntax that looks a lot like Python. 274 00:14:33,620 --> 00:14:39,290 I can say something like if number is equal to 1, 275 00:14:39,290 --> 00:14:42,710 then I'll go ahead and display the HTML content. 276 00:14:42,710 --> 00:14:46,990 Your coin flip is heads. 277 00:14:46,990 --> 00:14:51,560 Else if the number isn't 1, the only other option is 0. 278 00:14:51,560 --> 00:14:54,560 So your coin flip is tails. 279 00:14:54,560 --> 00:14:56,840 And then at the bottom, Jinja also requires 280 00:14:56,840 --> 00:15:02,490 me to have an end if, specifying here is the end of the if statement. 281 00:15:02,490 --> 00:15:06,830 And so here I've been able to add conditional logic to my HTML file. 282 00:15:06,830 --> 00:15:10,730 The ability to render different HTML depending upon whether 283 00:15:10,730 --> 00:15:12,420 or not a condition is true. 284 00:15:12,420 --> 00:15:16,310 I'm here saying if the number is equal to 1, the coin flip is heads, 285 00:15:16,310 --> 00:15:18,950 and otherwise the coin flip is tails, and we should just 286 00:15:18,950 --> 00:15:22,790 display one of these lines in the resulting HTML based 287 00:15:22,790 --> 00:15:25,030 on the value of the variable number. 288 00:15:25,030 --> 00:15:26,780 All right, so let's see what this actually 289 00:15:26,780 --> 00:15:29,780 looks like when a user tries to visit this web page. 290 00:15:29,780 --> 00:15:34,120 I'll restart my web server running Flask run. 291 00:15:34,120 --> 00:15:36,010 I'll go back now and refresh the page. 292 00:15:36,010 --> 00:15:36,760 And they're right. 293 00:15:36,760 --> 00:15:37,810 Your coin flip as heads. 294 00:15:37,810 --> 00:15:41,440 Presumably the value of the variable number was equal to 1. 295 00:15:41,440 --> 00:15:44,260 And so the result I got was that my coin flip is heads. 296 00:15:44,260 --> 00:15:47,380 But if I refresh the page, I now see my coin flip as tails, 297 00:15:47,380 --> 00:15:50,710 because it generated a different random number, 0 in this case, 298 00:15:50,710 --> 00:15:51,760 and now it's tails. 299 00:15:51,760 --> 00:15:55,690 And if I keep refreshing, sometimes I'll get tails, sometimes I'll get heads, 300 00:15:55,690 --> 00:15:57,670 and that's going to indicate a difference 301 00:15:57,670 --> 00:16:00,490 in what the value of the number variable was 302 00:16:00,490 --> 00:16:04,510 that determines what HTML ultimately gets sent back from my Flask web 303 00:16:04,510 --> 00:16:05,320 server. 304 00:16:05,320 --> 00:16:08,540 And again, if I view the actual source code here, 305 00:16:08,540 --> 00:16:10,880 I only see your coin flip as heads. 306 00:16:10,880 --> 00:16:12,800 I don't see a your coin flip is tails. 307 00:16:12,800 --> 00:16:14,990 I don't see the if statements that were there inside 308 00:16:14,990 --> 00:16:17,450 of the index.html template. 309 00:16:17,450 --> 00:16:21,080 The render template function handles the process of looking for variables, 310 00:16:21,080 --> 00:16:24,830 looking for conditions, and generating dynamic HTML that 311 00:16:24,830 --> 00:16:27,140 then gets sent back to the user. 312 00:16:27,140 --> 00:16:30,940 Let's now make our web page even more interactive by letting the user type 313 00:16:30,940 --> 00:16:32,690 something in, for example, and being taken 314 00:16:32,690 --> 00:16:36,790 to a page that uses what the user typed in as part of the response that gets 315 00:16:36,790 --> 00:16:38,030 sent back to them. 316 00:16:38,030 --> 00:16:43,212 So inside of index.html, I'll replace what we currently have with a form. 317 00:16:43,212 --> 00:16:45,170 This form is going to have an input field whose 318 00:16:45,170 --> 00:16:48,350 type is text where the user is going to be able to type in their name, 319 00:16:48,350 --> 00:16:49,550 for example. 320 00:16:49,550 --> 00:16:51,860 And we'll also have an input field whose type 321 00:16:51,860 --> 00:16:54,920 is submit that will let the user submit the form when 322 00:16:54,920 --> 00:16:57,170 they're done typing in their name. 323 00:16:57,170 --> 00:17:00,720 Now, in particular what should happen when we submit the form? 324 00:17:00,720 --> 00:17:03,950 Recall that every form can have an action of what route we're 325 00:17:03,950 --> 00:17:06,680 taken to when the form is submitted. 326 00:17:06,680 --> 00:17:08,720 Before we were writing our own web servers, 327 00:17:08,720 --> 00:17:12,740 we could specify the form of action to be google.com/search, for example, 328 00:17:12,740 --> 00:17:14,339 to search for something. 329 00:17:14,339 --> 00:17:17,690 But in this case, we can make the action a route of our own. 330 00:17:17,690 --> 00:17:22,490 And I'll make the route /hello, a route that I haven't created yet, 331 00:17:22,490 --> 00:17:26,329 but the idea of this is going to be that when I submit this form it is going 332 00:17:26,329 --> 00:17:31,310 to submit a request to /hello, and then the /hello route is going to need 333 00:17:31,310 --> 00:17:34,010 to figure out how to deal with that request. 334 00:17:34,010 --> 00:17:38,960 But inside of my Flask application, when my /hello route gets a request from 335 00:17:38,960 --> 00:17:41,510 a user, meaning the user submitted the form, 336 00:17:41,510 --> 00:17:45,200 I would like for inside of my application me to be able to access 337 00:17:45,200 --> 00:17:48,520 what it is the user typed in into the input field. 338 00:17:48,520 --> 00:17:52,340 And in order to do that, when you have a form where you're submitting some data, 339 00:17:52,340 --> 00:17:54,830 you'll generally want to give each of these input fields 340 00:17:54,830 --> 00:17:59,750 an attribute called name that is going to specify a name for the input field 341 00:17:59,750 --> 00:18:01,760 so that you can reference it later. 342 00:18:01,760 --> 00:18:06,422 Here I'll give this input field a name of, in this case, just name, 343 00:18:06,422 --> 00:18:08,630 because that is what I want the user to be typing in. 344 00:18:08,630 --> 00:18:10,460 I want the user to type in their name. 345 00:18:10,460 --> 00:18:13,650 If I instead wanted the user to type in their email, for instance, 346 00:18:13,650 --> 00:18:16,070 I might set the name of the input field equal to email 347 00:18:16,070 --> 00:18:17,850 instead or something else. 348 00:18:17,850 --> 00:18:20,020 But in this case, I'm asking for a name, so I'll 349 00:18:20,020 --> 00:18:23,030 give a name to this input field of name, because that's 350 00:18:23,030 --> 00:18:24,890 what I want the user to type in. 351 00:18:24,890 --> 00:18:29,720 So now let's add to application.py the /hello route that we're going to need 352 00:18:29,720 --> 00:18:32,390 in order to handle that form submission. 353 00:18:32,390 --> 00:18:35,300 So we'll go back here, and I'll remove the random number information 354 00:18:35,300 --> 00:18:36,000 from before. 355 00:18:36,000 --> 00:18:38,540 We're no longer going to be generating any random numbers. 356 00:18:38,540 --> 00:18:42,470 And I'll replace the /goodbye route with the /hello route, 357 00:18:42,470 --> 00:18:46,280 which is the route that we're going to go to when the user submits the form. 358 00:18:46,280 --> 00:18:48,140 I'll call the function hello. 359 00:18:48,140 --> 00:18:50,750 And when the user submits a form using a request 360 00:18:50,750 --> 00:18:53,300 method of GET, which is the default, if I 361 00:18:53,300 --> 00:18:56,750 want to access the parameters of that form submission, 362 00:18:56,750 --> 00:19:03,290 I can use syntax like request.args.get and then whatever input field 363 00:19:03,290 --> 00:19:05,360 I want to access the data for. 364 00:19:05,360 --> 00:19:08,570 Recall that in index.html, this input had 365 00:19:08,570 --> 00:19:13,500 a name of name, which was the name I gave to this particular input field. 366 00:19:13,500 --> 00:19:16,400 And so if I want to now access the user's name, whatever 367 00:19:16,400 --> 00:19:20,840 they typed into the form, well, I'll go ahead and go to request.args.get, 368 00:19:20,840 --> 00:19:24,080 and then I'll specify name as the input field 369 00:19:24,080 --> 00:19:26,480 that I'm trying to get information about. 370 00:19:26,480 --> 00:19:30,220 I'll save that information in a variable called name. 371 00:19:30,220 --> 00:19:36,310 And now let me return render template a new template called hello.html, 372 00:19:36,310 --> 00:19:41,230 for example, passing in to the HTML template a variable called 373 00:19:41,230 --> 00:19:47,090 name, which is set equal to whatever the current value of name happens to be. 374 00:19:47,090 --> 00:19:48,290 So what am I doing here? 375 00:19:48,290 --> 00:19:51,170 When the user submits the form in index.html, 376 00:19:51,170 --> 00:19:53,900 they'll be taken to the /hello route. 377 00:19:53,900 --> 00:19:55,760 What does the /hello route do? 378 00:19:55,760 --> 00:20:00,140 Well, it looks at the request and gets the name argument of the request. 379 00:20:00,140 --> 00:20:03,860 In other words, what it is the user typed in to the name input field 380 00:20:03,860 --> 00:20:05,210 inside of that form. 381 00:20:05,210 --> 00:20:07,790 We're saving that result in a variable called name, 382 00:20:07,790 --> 00:20:13,070 and then we're rendering hello.html and providing that name as a variable 383 00:20:13,070 --> 00:20:16,910 that the hello.html template is going to have access to. 384 00:20:16,910 --> 00:20:20,600 So inside of templates now, I'll need to create a new template. 385 00:20:20,600 --> 00:20:24,770 I already have index.html, but I'm not just rendering index.html. 386 00:20:24,770 --> 00:20:27,410 Here I'm rendering hello.html. 387 00:20:27,410 --> 00:20:31,730 So I'll create a new file called hello.html. 388 00:20:31,730 --> 00:20:35,180 And hello.html is going to look very similar to index.html. 389 00:20:35,180 --> 00:20:37,010 It's still going to have a title of hello. 390 00:20:37,010 --> 00:20:42,350 Except instead of a form, what I'm going to have here is hello comma, 391 00:20:42,350 --> 00:20:44,900 and then I'll plug in the value of the name. 392 00:20:44,900 --> 00:20:49,930 Curly brace, curly brace, name, exclamation point. 393 00:20:49,930 --> 00:20:54,070 So now I have an index.html template that has a form that I can submit that 394 00:20:54,070 --> 00:20:55,930 takes me to /hello. 395 00:20:55,930 --> 00:21:01,500 And when I go to /hello, application.py gets the user's name and then renders 396 00:21:01,500 --> 00:21:05,410 hello.html providing that name as an argument. 397 00:21:05,410 --> 00:21:09,250 And hello.html says hello to that person. 398 00:21:09,250 --> 00:21:10,420 Let's try it out. 399 00:21:10,420 --> 00:21:15,310 I'll run Flask run, which will start up my web server. 400 00:21:15,310 --> 00:21:18,870 And now if I refresh the page, I now see an HTML form, 401 00:21:18,870 --> 00:21:22,320 a place where I can type in my name, and then a place where I can submit 402 00:21:22,320 --> 00:21:25,320 the form in order to go to the /hello route. 403 00:21:25,320 --> 00:21:26,460 So let me try it out. 404 00:21:26,460 --> 00:21:30,230 I'll type in my name, and I'll go ahead and press the Submit button. 405 00:21:30,230 --> 00:21:32,070 All right, internal server error. 406 00:21:32,070 --> 00:21:33,520 Something went wrong. 407 00:21:33,520 --> 00:21:34,980 Let's try and figure it out. 408 00:21:34,980 --> 00:21:38,220 Up in the URL bar, I was taken to the /hello route. 409 00:21:38,220 --> 00:21:42,420 And you'll notice that here too we did include the GET parameters. 410 00:21:42,420 --> 00:21:46,740 Name equals Brian means that name was provided as an argument 411 00:21:46,740 --> 00:21:50,220 to this particular route as a GET parameter. 412 00:21:50,220 --> 00:21:52,380 So where's my server error coming from? 413 00:21:52,380 --> 00:21:54,300 Whenever you get an internal server error, 414 00:21:54,300 --> 00:21:58,170 you can often just look in the terminal section of your IDE 415 00:21:58,170 --> 00:22:02,200 where you were running Flask run to try and see what it is the error was. 416 00:22:02,200 --> 00:22:05,250 And here, all right, I'm getting a name error, 417 00:22:05,250 --> 00:22:11,010 request is not defined in application.py on line 13. 418 00:22:11,010 --> 00:22:14,175 All right, so let's go to application.py and take a look at line 13 419 00:22:14,175 --> 00:22:16,050 and see if we can figure out what went wrong. 420 00:22:16,050 --> 00:22:19,630 I set name equal to request.args.get name, 421 00:22:19,630 --> 00:22:22,080 but it's saying request is not defined. 422 00:22:22,080 --> 00:22:24,270 And all right, it turns out that request happens 423 00:22:24,270 --> 00:22:26,340 to be a feature that Flask gives us access 424 00:22:26,340 --> 00:22:30,690 to in order to give us information about the current request, the current person 425 00:22:30,690 --> 00:22:33,150 who is trying to request a particular page. 426 00:22:33,150 --> 00:22:35,130 But in order to use it, much like I needed 427 00:22:35,130 --> 00:22:38,190 to import render template to be able to use the render template 428 00:22:38,190 --> 00:22:42,782 function in Flask, I also need to import request. 429 00:22:42,782 --> 00:22:43,740 So that was my mistake. 430 00:22:43,740 --> 00:22:48,030 I need to import request as well in order to allow for Flask and Python 431 00:22:48,030 --> 00:22:52,660 to know what request actually is at this point inside of my function. 432 00:22:52,660 --> 00:22:56,052 So I've imported request, and now I'll go back to my web page 433 00:22:56,052 --> 00:22:58,260 or go back to the slash route, just the default route 434 00:22:58,260 --> 00:23:01,020 when I visit my web application for the first time. 435 00:23:01,020 --> 00:23:03,390 I'll type in my name, Brian. 436 00:23:03,390 --> 00:23:04,680 I'll press Submit. 437 00:23:04,680 --> 00:23:07,750 And now I'm taken to a page that says hello Brian. 438 00:23:07,750 --> 00:23:10,840 And it's all dependent upon these URL parameters. 439 00:23:10,840 --> 00:23:13,590 If I change the arguments, if I change the GET parameters 440 00:23:13,590 --> 00:23:18,780 by saying name equals Emma, for example, well, now the page says hello, Emma. 441 00:23:18,780 --> 00:23:22,260 And I can change those GET parameters or resubmit the form if I instead 442 00:23:22,260 --> 00:23:24,270 type David and then press Submit. 443 00:23:24,270 --> 00:23:26,110 Now the page says hello, David. 444 00:23:26,110 --> 00:23:29,100 And it's constantly generating new dynamic HTML, 445 00:23:29,100 --> 00:23:32,040 plugging in the value of name based on whatever it is 446 00:23:32,040 --> 00:23:35,150 the user submitted inside of that form. 447 00:23:35,150 --> 00:23:37,670 All right, so what might go wrong here, and where 448 00:23:37,670 --> 00:23:39,170 is there room for improvement? 449 00:23:39,170 --> 00:23:41,420 Well, if I go back to the main URL, go back 450 00:23:41,420 --> 00:23:45,050 to the default route of just slash, what would happen, for example, if I 451 00:23:45,050 --> 00:23:48,827 didn't type a name into the field and I just pressed the Submit button? 452 00:23:48,827 --> 00:23:50,660 Well, as you might guess, when I press this, 453 00:23:50,660 --> 00:23:53,822 I just get hello comma and then an exclamation point. 454 00:23:53,822 --> 00:23:56,030 All right, it seems like my web application right now 455 00:23:56,030 --> 00:24:01,040 isn't handling very well the situation where no information is provided inside 456 00:24:01,040 --> 00:24:03,320 of the variable that I pass in. 457 00:24:03,320 --> 00:24:05,780 All right, so let's look at application.py. 458 00:24:05,780 --> 00:24:10,880 And here inside of the hello function, I say name equals request.args.getname. 459 00:24:10,880 --> 00:24:13,520 But what I'd like to do is add some additional logic 460 00:24:13,520 --> 00:24:17,480 to handle what should happen if there was no name provided. 461 00:24:17,480 --> 00:24:19,770 And so here I can just use a Python condition. 462 00:24:19,770 --> 00:24:22,370 This is a Python function where I can use any arbitrary 463 00:24:22,370 --> 00:24:23,880 logic that I would like. 464 00:24:23,880 --> 00:24:27,470 And so here I could say something like if not name, 465 00:24:27,470 --> 00:24:30,710 meaning if no name was provided, what should happen? 466 00:24:30,710 --> 00:24:34,830 Well, here I'll go ahead and return a new template, render template. 467 00:24:34,830 --> 00:24:38,880 We'll call it failure.html, just indicating that something went wrong. 468 00:24:38,880 --> 00:24:41,370 I'll create a new template. 469 00:24:41,370 --> 00:24:42,660 New file. 470 00:24:42,660 --> 00:24:45,260 Call it failure.html. 471 00:24:45,260 --> 00:24:49,250 Inside of which it's going to look very much like hello.html, but instead 472 00:24:49,250 --> 00:24:52,940 of saying hello name, I'll instead display a message. 473 00:24:52,940 --> 00:24:57,040 You must provide a name. 474 00:24:57,040 --> 00:24:59,710 If I wanted to, I could even add some CSS styling here. 475 00:24:59,710 --> 00:25:02,560 I could add a style block and say, you know what, for the body, 476 00:25:02,560 --> 00:25:05,810 change the color to red, just to display some red text instead. 477 00:25:05,810 --> 00:25:08,560 But really all I want to do is display some information that says, 478 00:25:08,560 --> 00:25:10,660 you must provide a name here. 479 00:25:10,660 --> 00:25:13,390 All right, so let's give this web application a try. 480 00:25:13,390 --> 00:25:18,790 I'll go back into CS50 IDE and run Flask run to start up my web application. 481 00:25:18,790 --> 00:25:22,328 And now I'll go back to the default route of my web application 482 00:25:22,328 --> 00:25:24,370 where I see a form where I can type something in. 483 00:25:24,370 --> 00:25:27,340 Again, if you do type in an actual name like Emma and press Submit, 484 00:25:27,340 --> 00:25:28,850 you get hello, Emma. 485 00:25:28,850 --> 00:25:33,460 But if I go back now and just leave it blank and press Submit, 486 00:25:33,460 --> 00:25:37,770 now I get taken to an error message that just says, you must provide a name. 487 00:25:37,770 --> 00:25:39,520 And that's all because of the logic that's 488 00:25:39,520 --> 00:25:41,650 happening here in application.py. 489 00:25:41,650 --> 00:25:45,940 I'm able to return different templates depending upon different situations. 490 00:25:45,940 --> 00:25:49,730 I'm accessing the value of the name that was provided as an argument. 491 00:25:49,730 --> 00:25:54,100 And if no name was provided, then I'm rendering a failure.html template. 492 00:25:54,100 --> 00:25:59,050 But otherwise, I'm rendering hello.html, passing in that name as an argument 493 00:25:59,050 --> 00:25:59,920 as well. 494 00:25:59,920 --> 00:26:02,710 So your function doesn't just need to return one template. 495 00:26:02,710 --> 00:26:04,780 It can have conditional logic that determines 496 00:26:04,780 --> 00:26:07,540 that based on certain situations, you should return one template, 497 00:26:07,540 --> 00:26:09,430 but under other situations, you might want 498 00:26:09,430 --> 00:26:12,160 to return a different template instead. 499 00:26:12,160 --> 00:26:16,570 But one thing you might be noticing is that across all of these HTML files, 500 00:26:16,570 --> 00:26:18,580 I'm doing a fair bit of copy pasting. 501 00:26:18,580 --> 00:26:24,280 I copy pasted index.html into hello.html and I copy pasted hello.html 502 00:26:24,280 --> 00:26:25,870 into failure.html. 503 00:26:25,870 --> 00:26:27,970 So it feels like there's room for improvement 504 00:26:27,970 --> 00:26:31,210 here too in order to factor out some of this common code 505 00:26:31,210 --> 00:26:34,180 into just one HTML file. 506 00:26:34,180 --> 00:26:37,220 And in Flask with its templating system built in, 507 00:26:37,220 --> 00:26:39,470 there is a way for us to be able to do that. 508 00:26:39,470 --> 00:26:40,990 So here's what I'm going to do. 509 00:26:40,990 --> 00:26:44,500 Inside of templates, I'm going to create a new template that I'm just 510 00:26:44,500 --> 00:26:47,380 going to call layout.html. 511 00:26:47,380 --> 00:26:51,280 And what I want to include in layout.html is all of the HTML 512 00:26:51,280 --> 00:26:55,440 that's shared in common among all of my HTML files. 513 00:26:55,440 --> 00:26:57,390 So all right, what do I have in layout.html? 514 00:26:57,390 --> 00:27:01,760 Well, I'll have doc type HTML, HTML language equals English, 515 00:27:01,760 --> 00:27:05,620 a header section where I have a title that just says hello, 516 00:27:05,620 --> 00:27:07,480 and a body section. 517 00:27:07,480 --> 00:27:10,900 And important here is that inside of the body section, 518 00:27:10,900 --> 00:27:13,120 this is where information might differ. 519 00:27:13,120 --> 00:27:17,180 But every HTML page has a different body block, so to speak, 520 00:27:17,180 --> 00:27:20,140 where index has a block of information that belongs there, 521 00:27:20,140 --> 00:27:24,520 hello.html has a different block of information that belongs there too. 522 00:27:24,520 --> 00:27:28,750 And so what I'm going to include in layout.html is some syntax like this. 523 00:27:28,750 --> 00:27:33,940 I'm going to in curly braces and percent signs say block body 524 00:27:33,940 --> 00:27:36,520 and then end block. 525 00:27:36,520 --> 00:27:39,490 In other words, there is going to be a block of HTML 526 00:27:39,490 --> 00:27:46,550 called body that is going to be inserted right here in this part of layout.html. 527 00:27:46,550 --> 00:27:48,180 So what does that mean? 528 00:27:48,180 --> 00:27:51,020 Well, it means that inside of index.html, 529 00:27:51,020 --> 00:27:54,050 I can get rid of all of this stuff that isn't really relevant. 530 00:27:54,050 --> 00:27:58,460 The only relevant portion of index.html is the content of the body, 531 00:27:58,460 --> 00:28:01,400 this HTML form that I want to display. 532 00:28:01,400 --> 00:28:06,330 So everything else I can delete and just leave myself left with this form. 533 00:28:06,330 --> 00:28:10,070 And now inside of index.html, what I want to say 534 00:28:10,070 --> 00:28:17,370 is that this index.html file is going to extend layout.html. 535 00:28:17,370 --> 00:28:20,160 And then how is it going to extend layout.html? 536 00:28:20,160 --> 00:28:21,870 Well, it means we're going to include all 537 00:28:21,870 --> 00:28:28,080 of the content from layout.html inside of index.html with the change 538 00:28:28,080 --> 00:28:32,690 that we're going to add something into block body. 539 00:28:32,690 --> 00:28:39,410 And this HTML form is what we're going to put inside of that body block. 540 00:28:39,410 --> 00:28:41,390 So we've extended the basic layout file that 541 00:28:41,390 --> 00:28:43,820 just defines the general structure of the page, 542 00:28:43,820 --> 00:28:49,300 and then we've said inside the body section of that page, insert this form. 543 00:28:49,300 --> 00:28:53,460 All right, so now we can do a similar thing with hello.html. 544 00:28:53,460 --> 00:28:57,350 Instead of just saying hello name, I could instead 545 00:28:57,350 --> 00:29:07,620 extend layout.html and then inside of block body say hello comma name 546 00:29:07,620 --> 00:29:08,860 and then end block. 547 00:29:08,860 --> 00:29:11,683 548 00:29:11,683 --> 00:29:13,850 And we can do a similar thing here too with failure, 549 00:29:13,850 --> 00:29:16,740 where I can get rid of everything other than the body, 550 00:29:16,740 --> 00:29:24,080 extend layout.html, and then inside of block body include the message, 551 00:29:24,080 --> 00:29:28,680 you must provide a name, and then end the block. 552 00:29:28,680 --> 00:29:31,770 So now each of my HTML files is much shorter, 553 00:29:31,770 --> 00:29:34,140 because I'm only providing the information that 554 00:29:34,140 --> 00:29:36,750 is different across each of the HTML files. 555 00:29:36,750 --> 00:29:40,890 I factored out the HTML that's shared in common among all three of these HTML 556 00:29:40,890 --> 00:29:45,360 files into layout.html and put just the unique stuff 557 00:29:45,360 --> 00:29:49,930 inside of each of the individual HTML templates themselves. 558 00:29:49,930 --> 00:29:50,970 So let's try this. 559 00:29:50,970 --> 00:29:55,150 I'll go ahead and rerun the application by using Flask run. 560 00:29:55,150 --> 00:29:58,600 And now if I go back to the default route of my web page, 561 00:29:58,600 --> 00:30:00,310 I still see the same form. 562 00:30:00,310 --> 00:30:01,480 I can type in Emma. 563 00:30:01,480 --> 00:30:02,827 I still see hello, Emma. 564 00:30:02,827 --> 00:30:04,660 But now the advantage here is that if I ever 565 00:30:04,660 --> 00:30:07,420 wanted to change something about this application, 566 00:30:07,420 --> 00:30:10,530 for example, I wanted to change the title that appears 567 00:30:10,530 --> 00:30:14,920 or I wanted to change some styling across the entire application, 568 00:30:14,920 --> 00:30:17,950 I could just change the layout.html file, 569 00:30:17,950 --> 00:30:20,440 and that would change all of the HTML files 570 00:30:20,440 --> 00:30:24,580 that my web application uses, because each and every one of these HTML files 571 00:30:24,580 --> 00:30:28,110 is extending layout.html. 572 00:30:28,110 --> 00:30:30,090 Of course, what you might have noticed is 573 00:30:30,090 --> 00:30:34,620 that now if I leave the input field blank and just click on Submit, 574 00:30:34,620 --> 00:30:37,440 I see you must provide a name, but I've lost something. 575 00:30:37,440 --> 00:30:39,630 I've lost that red styling that I had before where 576 00:30:39,630 --> 00:30:41,670 the message showed up as red as well. 577 00:30:41,670 --> 00:30:43,270 How do I solve that problem? 578 00:30:43,270 --> 00:30:48,330 Well, inside of failure.html, I only have access to this body block. 579 00:30:48,330 --> 00:30:50,220 I don't have the ability to put something 580 00:30:50,220 --> 00:30:52,500 in the head section of the website anymore, 581 00:30:52,500 --> 00:30:55,440 because that's all inside of layout.html. 582 00:30:55,440 --> 00:30:59,300 But you can solve this just by adding a new block to layout.html. 583 00:30:59,300 --> 00:31:01,050 You can create as many blocks as you would 584 00:31:01,050 --> 00:31:04,140 like where you can insert custom code, and those blocks 585 00:31:04,140 --> 00:31:06,240 can have any name that you want. 586 00:31:06,240 --> 00:31:08,620 So up here in the header section of my web page, 587 00:31:08,620 --> 00:31:10,200 I'll go ahead and add a new block. 588 00:31:10,200 --> 00:31:15,180 I'll call it block style, because it's where I'll include the style code, 589 00:31:15,180 --> 00:31:17,280 and then end the block. 590 00:31:17,280 --> 00:31:20,700 And in fact, I can put that block style inside of style tags 591 00:31:20,700 --> 00:31:24,950 as well so that I can just include the style tags once 592 00:31:24,950 --> 00:31:29,300 and then display all the style information inside of it. 593 00:31:29,300 --> 00:31:36,220 So now inside of failure.html, I'll add a block style, inside 594 00:31:36,220 --> 00:31:43,210 of which I'll just say for the body, go ahead and give it a color of red, 595 00:31:43,210 --> 00:31:45,580 for example. 596 00:31:45,580 --> 00:31:49,490 So now if I go ahead and reload my web application 597 00:31:49,490 --> 00:31:51,830 and then reload this error message, you'll 598 00:31:51,830 --> 00:31:54,770 now see that you must provide a name is colored red. 599 00:31:54,770 --> 00:31:57,290 I was able to add a style block to my page 600 00:31:57,290 --> 00:32:00,530 where I was able to display some custom style information that 601 00:32:00,530 --> 00:32:03,650 got rendered as CSS in the page that the user sees 602 00:32:03,650 --> 00:32:05,730 when they go to this particular page. 603 00:32:05,730 --> 00:32:07,910 So this is the power that Flask gives us. 604 00:32:07,910 --> 00:32:11,480 The ability to define the routes that are able to look at information 605 00:32:11,480 --> 00:32:14,060 and then render templates that are dynamically generated. 606 00:32:14,060 --> 00:32:18,440 Different HTML based on the situation, taking advantage of features in Python 607 00:32:18,440 --> 00:32:22,220 like conditional logic and variables and other information as well. 608 00:32:22,220 --> 00:32:26,090 So now let's try and use all of that to build a useful application. 609 00:32:26,090 --> 00:32:29,420 Maybe we want to build an application that keeps track of tasks, like a to do 610 00:32:29,420 --> 00:32:30,750 list, for example. 611 00:32:30,750 --> 00:32:32,300 So let's give that a try. 612 00:32:32,300 --> 00:32:34,220 We'll go back into CS50 IDE. 613 00:32:34,220 --> 00:32:36,950 And let's create a new web application. 614 00:32:36,950 --> 00:32:39,500 Instead of hello, I'll create a new folder 615 00:32:39,500 --> 00:32:42,320 and we'll call it Tasks, inside of which, 616 00:32:42,320 --> 00:32:45,820 again, every Flask application needs a file called application.py 617 00:32:45,820 --> 00:32:49,100 where we're going to include the application 618 00:32:49,100 --> 00:32:53,300 code for what the routes are and what each of those routes should do. 619 00:32:53,300 --> 00:32:54,200 So all right. 620 00:32:54,200 --> 00:32:56,280 From Flask, import flask. 621 00:32:56,280 --> 00:32:59,030 And I'll import render template and request, because I'll probably 622 00:32:59,030 --> 00:33:00,800 end up needing those as well. 623 00:33:00,800 --> 00:33:04,710 I'll define my app, which is a Flask app, same as before. 624 00:33:04,710 --> 00:33:06,680 And now let me add a couple of routes. 625 00:33:06,680 --> 00:33:09,350 I'll add a default route, just slash, which 626 00:33:09,350 --> 00:33:12,140 is going to show me all of my tasks. 627 00:33:12,140 --> 00:33:16,070 For now, I'll just return tasks, but I'll come back to that. 628 00:33:16,070 --> 00:33:19,840 And I also want a route that lets me add a new task, for example. 629 00:33:19,840 --> 00:33:24,920 So app.route, we'll call it /add that lets me add a new task. 630 00:33:24,920 --> 00:33:27,830 Return add a new task. 631 00:33:27,830 --> 00:33:29,930 So far it doesn't actually work, but just want 632 00:33:29,930 --> 00:33:32,490 to give us a test to see how this might work. 633 00:33:32,490 --> 00:33:37,550 I'll go ahead and change directories into the tasks directory. 634 00:33:37,550 --> 00:33:41,920 And now I'll run Flask run to run this application. 635 00:33:41,920 --> 00:33:46,430 And now if I load the page, go into the default route, I see tasks. 636 00:33:46,430 --> 00:33:50,500 And if I go to /add, I see add a new task. 637 00:33:50,500 --> 00:33:55,497 All right, so let's try now to be able to actually implement this application. 638 00:33:55,497 --> 00:33:58,580 The first thing that I'm probably going to need are a couple of templates. 639 00:33:58,580 --> 00:34:02,740 So instead of Tasks, I'll create a new folder that I'll call Templates. 640 00:34:02,740 --> 00:34:05,890 And I'll create two templates, one to show me all of my tasks, 641 00:34:05,890 --> 00:34:08,320 and one template where I can begin to add things. 642 00:34:08,320 --> 00:34:11,120 But just so that they share some HTML in common, 643 00:34:11,120 --> 00:34:14,520 I'll create a new file called layout.html 644 00:34:14,520 --> 00:34:17,679 that is going to have all the HTML that these two 645 00:34:17,679 --> 00:34:20,150 templates are going to have in common. 646 00:34:20,150 --> 00:34:25,290 So doc type, HTML, HTML, head, the title is 647 00:34:25,290 --> 00:34:28,020 going to be tasks, and then the body. 648 00:34:28,020 --> 00:34:31,650 And here I'm going to add a block called body 649 00:34:31,650 --> 00:34:33,880 that I can use to plug in some information 650 00:34:33,880 --> 00:34:37,150 here in each of my individual templates. 651 00:34:37,150 --> 00:34:41,810 So I'll create a new template that all call tasks.html. 652 00:34:41,810 --> 00:34:47,389 And inside of tasks.html, I'm going to extend layout.html 653 00:34:47,389 --> 00:34:52,969 and then just include some custom information inside of block body. 654 00:34:52,969 --> 00:34:57,380 Here I'll just have an H1, a big heading at the top that says Tasks. 655 00:34:57,380 --> 00:35:00,670 And then maybe I want here a list of tasks. 656 00:35:00,670 --> 00:35:04,830 And to create a list in HTML, you can use the UL tag, 657 00:35:04,830 --> 00:35:08,870 UL short for Unordered List, inside of which 658 00:35:08,870 --> 00:35:13,580 you have a whole bunch of LI tags, LI standing for a List Item. 659 00:35:13,580 --> 00:35:20,550 So LI item one, LI item two, LI item three. 660 00:35:20,550 --> 00:35:23,270 So this will create a bulleted list of items for me. 661 00:35:23,270 --> 00:35:25,910 And maybe at the bottom, I want to link to the page 662 00:35:25,910 --> 00:35:29,130 where I can create a new task, for example. 663 00:35:29,130 --> 00:35:32,087 So let me add a link, a href. 664 00:35:32,087 --> 00:35:33,170 Where should this take me? 665 00:35:33,170 --> 00:35:36,080 Well, let's have it take me to /new. 666 00:35:36,080 --> 00:35:38,540 That's the route that lets me create a new task. 667 00:35:38,540 --> 00:35:41,758 And let's say create a new task. 668 00:35:41,758 --> 00:35:45,050 So a button here at the bottom that will basically act as a link that will take 669 00:35:45,050 --> 00:35:46,070 me to /new. 670 00:35:46,070 --> 00:35:48,790 671 00:35:48,790 --> 00:35:52,390 So now tasks instead of just returning the string tasks, 672 00:35:52,390 --> 00:35:54,940 I'll have it return a template. 673 00:35:54,940 --> 00:35:59,010 In particular, tasks.html. 674 00:35:59,010 --> 00:36:00,560 What should add do? 675 00:36:00,560 --> 00:36:05,720 We'll have this render a template as well called add.html. 676 00:36:05,720 --> 00:36:11,320 And here I'll create a new template called add.html. 677 00:36:11,320 --> 00:36:16,330 And add.html will also extend layout.html. 678 00:36:16,330 --> 00:36:22,520 And then inside of block body, what I'd like to do is add some sort of form. 679 00:36:22,520 --> 00:36:25,140 And this form is going to have an input whose type is 680 00:36:25,140 --> 00:36:30,320 text and an input whose type is submit. 681 00:36:30,320 --> 00:36:32,800 All right, so let's take a look at this web application. 682 00:36:32,800 --> 00:36:35,330 I'll restart by running Flask run and see 683 00:36:35,330 --> 00:36:39,150 what this web application actually looks like, at least right now. 684 00:36:39,150 --> 00:36:42,100 So I'll go to the default route of the web application. 685 00:36:42,100 --> 00:36:45,253 All right, so when I visit this page, I see tasks at the top, 686 00:36:45,253 --> 00:36:46,920 and then I see a bulleted list of items. 687 00:36:46,920 --> 00:36:49,080 Item one, item two, item three. 688 00:36:49,080 --> 00:36:52,590 And then down at the bottom, I see a link that lets me create a new task. 689 00:36:52,590 --> 00:36:54,600 Let's try clicking it and see where it takes me. 690 00:36:54,600 --> 00:36:56,160 Create a new task. 691 00:36:56,160 --> 00:36:57,420 All right, not found. 692 00:36:57,420 --> 00:37:01,110 This is one of those 404 errors where I'm trying to request a page, 693 00:37:01,110 --> 00:37:02,380 but it's not there. 694 00:37:02,380 --> 00:37:03,770 So what went wrong? 695 00:37:03,770 --> 00:37:06,930 Well, I'm trying to access the root called /new. 696 00:37:06,930 --> 00:37:08,882 And let's go back to application.py. 697 00:37:08,882 --> 00:37:11,340 And all right, it looks like I just gave it the wrong name. 698 00:37:11,340 --> 00:37:16,350 I tried to redirect to /new, but the actual name of the route is /add. 699 00:37:16,350 --> 00:37:18,775 And so I tried to visit a route that didn't exist. 700 00:37:18,775 --> 00:37:21,150 And when you try to visit a route that doesn't yet exist, 701 00:37:21,150 --> 00:37:25,860 the natural response for the web server is to respond with a 404 not found. 702 00:37:25,860 --> 00:37:28,620 The page you tried to request does not exist. 703 00:37:28,620 --> 00:37:29,730 How do I fix it? 704 00:37:29,730 --> 00:37:34,020 Well, inside of tasks.html, instead of linking to /new, 705 00:37:34,020 --> 00:37:39,450 I'll instead link to /add to be the page where I want to create a new task. 706 00:37:39,450 --> 00:37:44,710 All right, now if I go ahead and reload this web server by running Flask run, 707 00:37:44,710 --> 00:37:45,960 let's try it. 708 00:37:45,960 --> 00:37:49,180 If I go back to the default route, I see a list of tasks in addition 709 00:37:49,180 --> 00:37:53,130 to a Create A New Task link where when I click on that Create A New Task link, 710 00:37:53,130 --> 00:37:55,600 all right, now I'm taken to a page where I can actually 711 00:37:55,600 --> 00:37:58,630 type in the name of a new task and submit it. 712 00:37:58,630 --> 00:38:01,150 Of course, it's not really doing anything just yet, 713 00:38:01,150 --> 00:38:03,050 but let's get to that now. 714 00:38:03,050 --> 00:38:08,087 Let's go back to CS50 IDE and take a look at add.html. 715 00:38:08,087 --> 00:38:10,170 There are a couple of things I'll want to do here. 716 00:38:10,170 --> 00:38:12,530 One is that I might like to signal to the user 717 00:38:12,530 --> 00:38:16,130 that inside of this text field, they should be typing in the name of a task. 718 00:38:16,130 --> 00:38:20,480 So we can add an additional attribute to this input field called placeholder 719 00:38:20,480 --> 00:38:23,660 and just say task name, for example. 720 00:38:23,660 --> 00:38:26,928 Some placeholder that's going to be there by default so that the user knows 721 00:38:26,928 --> 00:38:29,720 when they visit this page what it is that they should be typing in, 722 00:38:29,720 --> 00:38:30,795 for example. 723 00:38:30,795 --> 00:38:34,280 And additionally, just as before, if I want my program 724 00:38:34,280 --> 00:38:39,300 to be able to access these input fields, I can give them a name. 725 00:38:39,300 --> 00:38:43,970 So I'm going to call this input task so that later on on the receiving 726 00:38:43,970 --> 00:38:47,300 end in my application.py file, when I receive a form 727 00:38:47,300 --> 00:38:52,040 submission from add.html, I can look for a form field called task 728 00:38:52,040 --> 00:38:54,410 to get at that information. 729 00:38:54,410 --> 00:38:58,390 So what should my form do in order to actually submit data? 730 00:38:58,390 --> 00:39:00,490 Well, here we can take advantage of a convention, 731 00:39:00,490 --> 00:39:06,070 recalling again that web routes can accept requests using multiple request 732 00:39:06,070 --> 00:39:07,060 methods. 733 00:39:07,060 --> 00:39:10,630 GET is usually the request method we'll use by default when you just 734 00:39:10,630 --> 00:39:12,222 want to get a page. 735 00:39:12,222 --> 00:39:13,930 But there's another request method that's 736 00:39:13,930 --> 00:39:18,070 often used when I want to send data to a particular route, 737 00:39:18,070 --> 00:39:19,990 and that method is called POST. 738 00:39:19,990 --> 00:39:22,660 So GET for just getting information for a page 739 00:39:22,660 --> 00:39:27,920 and POST if I actually want to send data to update my task list, for example. 740 00:39:27,920 --> 00:39:34,810 And so here my form's action I still want to be /add to add a new task. 741 00:39:34,810 --> 00:39:38,470 But the method I'm going to use, which by default is GET, 742 00:39:38,470 --> 00:39:41,170 I'm going to instead say is POST. 743 00:39:41,170 --> 00:39:44,440 I want to use the POST request method to indicate 744 00:39:44,440 --> 00:39:49,160 when I'm making this request that I'm trying to send data to the server. 745 00:39:49,160 --> 00:39:52,660 So all right, how can I leverage that information now inside 746 00:39:52,660 --> 00:39:54,490 of application.py? 747 00:39:54,490 --> 00:39:58,030 Well, first and foremost, by default, routes in Flask 748 00:39:58,030 --> 00:40:00,730 only accept the GET request method. 749 00:40:00,730 --> 00:40:03,880 And what I would like is for /add, this route, 750 00:40:03,880 --> 00:40:07,930 to be able to accept both GET and POST requests. 751 00:40:07,930 --> 00:40:12,103 If I send a GET request to /add, meaning I'd like to get the page, 752 00:40:12,103 --> 00:40:13,270 then I just want to do this. 753 00:40:13,270 --> 00:40:14,380 Return this template. 754 00:40:14,380 --> 00:40:16,810 The display is the form where you can type in a task 755 00:40:16,810 --> 00:40:18,490 that you would like to add. 756 00:40:18,490 --> 00:40:22,760 But if the /add route receives a POST request, 757 00:40:22,760 --> 00:40:27,490 meaning someone submitted data to /add, then instead of displaying a form, 758 00:40:27,490 --> 00:40:32,150 I went to instead actually add that task to my list of tasks. 759 00:40:32,150 --> 00:40:33,860 So how am I going to do that? 760 00:40:33,860 --> 00:40:38,830 Well, first I'm going to specify for this route /add that I should accept 761 00:40:38,830 --> 00:40:41,040 multiple request methods. 762 00:40:41,040 --> 00:40:44,410 And I can do that by adding an argument called methods 763 00:40:44,410 --> 00:40:47,320 that's set equal to a list of the allowed request methods 764 00:40:47,320 --> 00:40:48,520 that I want to support. 765 00:40:48,520 --> 00:40:50,260 By default, it's just GET. 766 00:40:50,260 --> 00:40:54,820 But here I want to say allow both GET and POST requests. 767 00:40:54,820 --> 00:40:59,290 So GET and POST requests can be received by this /add route. 768 00:40:59,290 --> 00:41:01,570 And what we'd like to do is add some logic, 769 00:41:01,570 --> 00:41:03,910 such that if the request is a GET request, 770 00:41:03,910 --> 00:41:07,720 I just display the page that will let the user type in a new task what 771 00:41:07,720 --> 00:41:08,800 they need to do. 772 00:41:08,800 --> 00:41:11,330 And if the request method is a POST request, 773 00:41:11,330 --> 00:41:16,120 meaning they're sending data to /add, then what I want to do is add that task 774 00:41:16,120 --> 00:41:17,970 to their list of things to do. 775 00:41:17,970 --> 00:41:19,940 So let's actually try and write this. 776 00:41:19,940 --> 00:41:21,980 So let's go back to our add function. 777 00:41:21,980 --> 00:41:24,310 And I want to add some conditional logic here 778 00:41:24,310 --> 00:41:30,670 that says that if request.method equals GET, meaning if it's a GET request, 779 00:41:30,670 --> 00:41:32,920 then the user is just trying to get this page, 780 00:41:32,920 --> 00:41:36,340 so I should return the add.html page, the form that 781 00:41:36,340 --> 00:41:40,120 lets the user type anything they need to do and click the Submit button. 782 00:41:40,120 --> 00:41:43,120 When they actually do submit, though, then the request method 783 00:41:43,120 --> 00:41:44,110 is going to be POST. 784 00:41:44,110 --> 00:41:45,970 They're sending data to us. 785 00:41:45,970 --> 00:41:48,978 So here I could say elif request.method equals POST, 786 00:41:48,978 --> 00:41:50,770 but I'm only accepting two request methods. 787 00:41:50,770 --> 00:41:54,130 So if the request method isn't get, it must be POST. 788 00:41:54,130 --> 00:41:56,230 So I'll just say else. 789 00:41:56,230 --> 00:41:57,590 What do I want to do? 790 00:41:57,590 --> 00:41:59,110 Well, where is this task stored? 791 00:41:59,110 --> 00:42:03,940 The thing that I need to do is going to be stored in request.form.get. 792 00:42:03,940 --> 00:42:08,710 request.form.get lets me access data from the form that 793 00:42:08,710 --> 00:42:10,630 was submitted via POST. 794 00:42:10,630 --> 00:42:12,790 And what was the name of that input field? 795 00:42:12,790 --> 00:42:15,330 Well, its name was task. 796 00:42:15,330 --> 00:42:19,480 So all right, inside of application.py, I'll say the thing to do 797 00:42:19,480 --> 00:42:25,090 is request.form.get and then whatever thing had a name of task. 798 00:42:25,090 --> 00:42:28,060 That input field is what's going to be stored inside 799 00:42:28,060 --> 00:42:30,640 of this variable called to do. 800 00:42:30,640 --> 00:42:34,600 And now what I'd like to do is add this to do to a list of things 801 00:42:34,600 --> 00:42:36,040 that I need to do. 802 00:42:36,040 --> 00:42:38,800 So I'll go ahead and create, in this case, just a global variable 803 00:42:38,800 --> 00:42:43,000 in application.py called to dos, which is going to start out just 804 00:42:43,000 --> 00:42:44,350 by being an empty list. 805 00:42:44,350 --> 00:42:47,330 Starting out with no things that I need to do. 806 00:42:47,330 --> 00:42:51,420 But when I submit this form via POST, I'll get the task, 807 00:42:51,420 --> 00:42:57,070 and then I'll say todos.append to do. 808 00:42:57,070 --> 00:43:01,080 I'm adding to the end of the to do list the thing 809 00:43:01,080 --> 00:43:04,460 that I need to do that was just submitted via that form. 810 00:43:04,460 --> 00:43:06,120 But what should happen next? 811 00:43:06,120 --> 00:43:09,150 All right, so I've added the thing to do to this list of to dos. 812 00:43:09,150 --> 00:43:10,690 So what I need to do now? 813 00:43:10,690 --> 00:43:12,600 Well, what I need to do now is I'd really 814 00:43:12,600 --> 00:43:16,390 like to just display the list of tasks that the user needs to do. 815 00:43:16,390 --> 00:43:19,590 In other words, I'd like to just redirect the user back 816 00:43:19,590 --> 00:43:24,850 to this default route which displays their list of tasks, for example. 817 00:43:24,850 --> 00:43:25,800 And I can do that. 818 00:43:25,800 --> 00:43:31,950 Rather than returning a template, I can first import redirect from Flask. 819 00:43:31,950 --> 00:43:35,280 And now here rather than return render template something, 820 00:43:35,280 --> 00:43:39,000 I can return redirect followed by the route 821 00:43:39,000 --> 00:43:42,390 that I would like to redirect the user to, which in this case 822 00:43:42,390 --> 00:43:45,300 is just the slash route. 823 00:43:45,300 --> 00:43:49,485 So all right, I'll go ahead and rerun the server by running Flask run. 824 00:43:49,485 --> 00:43:52,310 And now let's take a look at this. 825 00:43:52,310 --> 00:43:53,830 I'll refresh the page. 826 00:43:53,830 --> 00:43:57,460 And here I see that I have a list of tasks, item one, item two, item three. 827 00:43:57,460 --> 00:44:00,880 Let me create a new task and type in a task name, 828 00:44:00,880 --> 00:44:03,020 something like do the dishes. 829 00:44:03,020 --> 00:44:08,720 I'll press Submit and all right, I'm redirected back to this list of tasks. 830 00:44:08,720 --> 00:44:13,080 But of course, this list of tasks right now isn't actually showing me the task. 831 00:44:13,080 --> 00:44:16,220 It's not showing me do the dishes among the other things that I need to do. 832 00:44:16,220 --> 00:44:20,150 It's right now only showing me item one, item two, item three, 833 00:44:20,150 --> 00:44:24,500 because I literally said inside of tasks.html, what should you show? 834 00:44:24,500 --> 00:44:28,280 An unordered list that has three items, item one, item two, item three. 835 00:44:28,280 --> 00:44:30,320 So let's fix that now. 836 00:44:30,320 --> 00:44:33,860 Let's go ahead and replace instead of all these list items, item one, 837 00:44:33,860 --> 00:44:39,330 item two, item three, let's loop through all of the things that I need to do. 838 00:44:39,330 --> 00:44:40,590 How am I going to do that? 839 00:44:40,590 --> 00:44:45,380 Well inside of application.py, here's my route that renders tasks.html. 840 00:44:45,380 --> 00:44:49,340 And what I would like to do is give tasks.html access 841 00:44:49,340 --> 00:44:52,970 to this list called to dos, which is my list of all the things 842 00:44:52,970 --> 00:44:54,710 that I need to do. 843 00:44:54,710 --> 00:45:00,080 So I'll add to render template tasks.html a variable that task.html 844 00:45:00,080 --> 00:45:01,730 is going to have access to. 845 00:45:01,730 --> 00:45:05,930 I'll call that variable to dos and just set it equal to to dos, 846 00:45:05,930 --> 00:45:09,980 the name of this variable in Python that represents the list of all the things 847 00:45:09,980 --> 00:45:11,900 that I need to do. 848 00:45:11,900 --> 00:45:16,760 Now, inside of tasks.html, let's implement this logic. 849 00:45:16,760 --> 00:45:20,360 Instead of these three list items, item one, item two, item three, 850 00:45:20,360 --> 00:45:25,680 let me actually loop over this list of tasks to display each one one by one. 851 00:45:25,680 --> 00:45:26,880 How do I do that? 852 00:45:26,880 --> 00:45:30,830 Well, in the same way that in this template before we could add conditions 853 00:45:30,830 --> 00:45:35,210 by using curly brace percent sign and then if something, 854 00:45:35,210 --> 00:45:37,400 the syntax will be very similar here where 855 00:45:37,400 --> 00:45:41,150 I can just say for to do in to dos. 856 00:45:41,150 --> 00:45:45,470 Loop over this list of things to do and call each individual item in the list 857 00:45:45,470 --> 00:45:46,880 to do. 858 00:45:46,880 --> 00:45:49,730 I'll have to end it with an end for in the same way 859 00:45:49,730 --> 00:45:52,760 that I ended my if statements with an end if. 860 00:45:52,760 --> 00:45:56,477 And now what should I do for each one of these to dos? 861 00:45:56,477 --> 00:45:58,310 Well, for each one of these to dos, I'd like 862 00:45:58,310 --> 00:46:01,700 to create a list item for it, an LI element. 863 00:46:01,700 --> 00:46:06,770 And the content of that list item should be whatever the to do actually is. 864 00:46:06,770 --> 00:46:10,790 And so here, I'll use curly brace syntax to say, take that to do 865 00:46:10,790 --> 00:46:13,160 and plug it in right here. 866 00:46:13,160 --> 00:46:17,340 So the effect of this is going to be that I'll create an unordered list, 867 00:46:17,340 --> 00:46:21,410 and then I'll loop over each one of the things in my list called to dos, 868 00:46:21,410 --> 00:46:25,370 calling each individual item in that list to do. 869 00:46:25,370 --> 00:46:29,570 And for each of those individual items, we will create a new list item 870 00:46:29,570 --> 00:46:33,540 element in HTML, and the content of that list item element 871 00:46:33,540 --> 00:46:37,120 will just be the name of the thing that I need to do. 872 00:46:37,120 --> 00:46:38,980 All right, so let's give it a try. 873 00:46:38,980 --> 00:46:42,890 I'll run Flask run to go ahead and run this web application. 874 00:46:42,890 --> 00:46:44,570 We'll go back and we'll refresh. 875 00:46:44,570 --> 00:46:46,570 And we'll notice now the task list is empty, 876 00:46:46,570 --> 00:46:48,580 because I start out with no tasks. 877 00:46:48,580 --> 00:46:52,600 Let me create a new task, and I'll just say do the dishes, for example, 878 00:46:52,600 --> 00:46:54,077 and submit that. 879 00:46:54,077 --> 00:46:54,660 And all right. 880 00:46:54,660 --> 00:46:58,320 Now I see a task list that has one bullet point that 881 00:46:58,320 --> 00:47:03,740 just says do the dishes, the first thing on my list of things that I need to do. 882 00:47:03,740 --> 00:47:04,870 I can add a new task. 883 00:47:04,870 --> 00:47:05,740 Create A New Task. 884 00:47:05,740 --> 00:47:08,560 I'll add one like answer email, for example. 885 00:47:08,560 --> 00:47:09,760 Click Submit. 886 00:47:09,760 --> 00:47:12,890 And all right, we've added a new task to the list of things to do. 887 00:47:12,890 --> 00:47:15,430 And we can see what the actual HTML looks like here. 888 00:47:15,430 --> 00:47:19,510 If I go to View, Developer, and then View Source, 889 00:47:19,510 --> 00:47:22,700 we can see that here inside the body of my web page, 890 00:47:22,700 --> 00:47:25,120 I have that big heading at the top that justice tasks, 891 00:47:25,120 --> 00:47:27,220 and then I have an unordered list where I'm 892 00:47:27,220 --> 00:47:30,550 looping over all of the items in my list of things to do 893 00:47:30,550 --> 00:47:32,270 and showing each one at a time. 894 00:47:32,270 --> 00:47:34,330 Here's a list item that says do the dishes. 895 00:47:34,330 --> 00:47:37,500 Here's a list item that says answer email. 896 00:47:37,500 --> 00:47:40,660 So I've been able to create dynamically generated HTML 897 00:47:40,660 --> 00:47:42,490 based on the values of a variable. 898 00:47:42,490 --> 00:47:45,250 And when you submit a form, we're updating that variable 899 00:47:45,250 --> 00:47:48,880 so that your task list always shows you the list of all of the things 900 00:47:48,880 --> 00:47:50,713 that you currently need to do. 901 00:47:50,713 --> 00:47:52,630 And so this is the power of Flask, the ability 902 00:47:52,630 --> 00:47:55,150 to generate these dynamic web pages. 903 00:47:55,150 --> 00:47:57,770 Now, let's try and make one final modification just 904 00:47:57,770 --> 00:47:59,590 to optimize this a little bit more. 905 00:47:59,590 --> 00:48:02,620 Right now if you go to create task and go to a task name 906 00:48:02,620 --> 00:48:06,760 and just click Submit without typing something in, what happens? 907 00:48:06,760 --> 00:48:08,640 Well, we just get an empty bullet point. 908 00:48:08,640 --> 00:48:10,390 Because as you might imagine, what's going 909 00:48:10,390 --> 00:48:13,750 to happen is that we're submitting the form, the name of the task 910 00:48:13,750 --> 00:48:16,360 is just the empty string, nothing was typed in, 911 00:48:16,360 --> 00:48:18,490 and so we just get this empty bullet point, which 912 00:48:18,490 --> 00:48:20,750 probably isn't what we want to do. 913 00:48:20,750 --> 00:48:22,780 So let's try to fix this now. 914 00:48:22,780 --> 00:48:28,870 And we can fix this by adding some JavaScript, for example, to add.html. 915 00:48:28,870 --> 00:48:33,030 Here below this form, I'll go ahead and add a script 916 00:48:33,030 --> 00:48:35,770 where I can add some JavaScript code. 917 00:48:35,770 --> 00:48:41,710 And what I'd like to do is I only want to enable this Submit button if there's 918 00:48:41,710 --> 00:48:45,020 actually some text inside of this task. 919 00:48:45,020 --> 00:48:47,350 So what I need to be able to do is somehow 920 00:48:47,350 --> 00:48:49,610 access both of these input fields. 921 00:48:49,610 --> 00:48:51,430 So I'll give each of them an ID. 922 00:48:51,430 --> 00:48:54,970 I'll give this one an ID of submit, and I'll 923 00:48:54,970 --> 00:49:00,040 give this field where I'm typing in the task name an ID of task. 924 00:49:00,040 --> 00:49:04,240 Recall again that these IDs are just unique identifiers for these input 925 00:49:04,240 --> 00:49:09,190 fields so that I in my JavaScript code can then reference that information. 926 00:49:09,190 --> 00:49:12,250 So inside of script, what am I then going to do? 927 00:49:12,250 --> 00:49:18,240 Well, what I want to say is document.queryselector 928 00:49:18,240 --> 00:49:20,660 the thing with the ID of task. 929 00:49:20,660 --> 00:49:25,660 Any time I type something into the task, whether it's typing a new character 930 00:49:25,660 --> 00:49:28,840 or typing the Delete key, I would like to check 931 00:49:28,840 --> 00:49:31,510 is there something currently inside of the text field? 932 00:49:31,510 --> 00:49:34,360 And if not, then you should disable the Submit button. 933 00:49:34,360 --> 00:49:37,660 So I'll go ahead and say on key up, which 934 00:49:37,660 --> 00:49:41,170 is an event that happens whenever I lift my finger off of a key, 935 00:49:41,170 --> 00:49:45,180 for example, whether it be a character key or the Backspace key. 936 00:49:45,180 --> 00:49:48,800 And when that happens, I'll go ahead and run this function. 937 00:49:48,800 --> 00:49:50,790 What should the function do? 938 00:49:50,790 --> 00:49:53,810 Well, the function should check, is there's something actually typed 939 00:49:53,810 --> 00:49:56,670 in to this task input field? 940 00:49:56,670 --> 00:49:57,770 How do I express that? 941 00:49:57,770 --> 00:50:03,020 Well, it's going to be a condition where I say if document.queryselector 942 00:50:03,020 --> 00:50:10,790 task.value is equal to the empty string, if I take the input field, 943 00:50:10,790 --> 00:50:13,010 look at its value, and it's equal to nothing, 944 00:50:13,010 --> 00:50:15,990 there's nothing there, well then what do I want to do? 945 00:50:15,990 --> 00:50:18,780 Well, I want to disable the Submit button. 946 00:50:18,780 --> 00:50:22,010 So I want to say, all right, let's go ahead in document.queryselector 947 00:50:22,010 --> 00:50:27,050 find the part of the HTML page that has an ID of submit 948 00:50:27,050 --> 00:50:32,700 and set its disabled attribute equal to true. 949 00:50:32,700 --> 00:50:36,990 Else, in other words, if there is something typed into the task field, 950 00:50:36,990 --> 00:50:39,300 then we're going to take the Submit button 951 00:50:39,300 --> 00:50:42,850 and set its disabled attribute to false. 952 00:50:42,850 --> 00:50:45,600 So let's talk through the logic here and just get an understanding 953 00:50:45,600 --> 00:50:47,130 for what it is that's happening. 954 00:50:47,130 --> 00:50:49,470 I'm adding an event listener to the thing 955 00:50:49,470 --> 00:50:51,840 that has an ID of task, which is that input 956 00:50:51,840 --> 00:50:54,230 field where I can type in a task name. 957 00:50:54,230 --> 00:50:57,150 And I'm saying every time I lift my finger off of a key, 958 00:50:57,150 --> 00:51:01,200 you should run this function that follows here, this anonymous function. 959 00:51:01,200 --> 00:51:05,250 What the function is doing is saying, all right, check that task input field 960 00:51:05,250 --> 00:51:06,960 and see what its value is. 961 00:51:06,960 --> 00:51:09,310 If its value is the empty string, in other words, 962 00:51:09,310 --> 00:51:12,550 nobody has typed anything in, then disable the Submit button. 963 00:51:12,550 --> 00:51:14,370 So you can't submit the form. 964 00:51:14,370 --> 00:51:19,750 Otherwise, set disabled equal to false, meaning do enable it. 965 00:51:19,750 --> 00:51:23,000 And then the last step is just to say, all right, for this input field here, 966 00:51:23,000 --> 00:51:25,960 do I want it to be enabled or disabled by default? 967 00:51:25,960 --> 00:51:28,180 I probably want it to be disabled by default, 968 00:51:28,180 --> 00:51:31,450 because by default, there is no text inside of the text field. 969 00:51:31,450 --> 00:51:35,350 So I'll add a disabled attribute to this input. 970 00:51:35,350 --> 00:51:40,930 Let's try it out now I'll go ahead and rerun the application, Flask run. 971 00:51:40,930 --> 00:51:42,670 And now I'll reload. 972 00:51:42,670 --> 00:51:44,200 Create A New Task. 973 00:51:44,200 --> 00:51:48,200 And notice now that by default, the Submit button is grayed out. 974 00:51:48,200 --> 00:51:51,970 It's not until I actually start typing something, like answer email, 975 00:51:51,970 --> 00:51:54,610 that you start to see the Submit button now enabled. 976 00:51:54,610 --> 00:51:57,490 But if I go back here and backspace, backspace, backspace 977 00:51:57,490 --> 00:52:00,790 all the way until there is no more characters, watch what happens. 978 00:52:00,790 --> 00:52:04,030 Press Backspace one more time, and the Submit button disables. 979 00:52:04,030 --> 00:52:06,070 You're no longer able to click it, because now I 980 00:52:06,070 --> 00:52:09,820 have some JavaScript code that's performing effectively some validation. 981 00:52:09,820 --> 00:52:12,280 JavaScript code that's checking whether or not something 982 00:52:12,280 --> 00:52:16,670 is actually typed into this input field and then responding appropriately. 983 00:52:16,670 --> 00:52:19,330 So here now we've been able to mix HTML as well 984 00:52:19,330 --> 00:52:23,470 as JavaScript inside of these templates that Flask is rendering to the user 985 00:52:23,470 --> 00:52:27,010 so that we can really create an interactive experience on this web page 986 00:52:27,010 --> 00:52:27,960 that we're creating. 987 00:52:27,960 --> 00:52:30,820 I press Submit, and we now see that answer email 988 00:52:30,820 --> 00:52:33,730 is added to this list of tasks. 989 00:52:33,730 --> 00:52:38,650 Of course, what you might notice here is that every time I restart the Flask web 990 00:52:38,650 --> 00:52:42,970 server, I lose access to all of the tasks that I previously created. 991 00:52:42,970 --> 00:52:47,000 If I go back here, Control C to exit out of the Flask web server, 992 00:52:47,000 --> 00:52:51,820 and then I rerun Flask run, for example, now when I go back to my task list 993 00:52:51,820 --> 00:52:55,350 and reload the page, my tasks go away. 994 00:52:55,350 --> 00:52:56,260 Why is that? 995 00:52:56,260 --> 00:53:01,780 Well, every time I reload the web server, it's rerunning application.py. 996 00:53:01,780 --> 00:53:04,870 And this to dos variable, which is my list of things to do, 997 00:53:04,870 --> 00:53:07,390 is getting reset back to the empty list. 998 00:53:07,390 --> 00:53:10,630 It's just being stored as a variable in memory in my program. 999 00:53:10,630 --> 00:53:13,030 And so when I quit the web server and restart it, 1000 00:53:13,030 --> 00:53:15,970 it gets reset back to the empty list again. 1001 00:53:15,970 --> 00:53:18,400 In practice, though, if you really want to store data then 1002 00:53:18,400 --> 00:53:20,260 in your web application, you're probably going 1003 00:53:20,260 --> 00:53:22,385 to want to store it somewhere else rather than just 1004 00:53:22,385 --> 00:53:25,450 inside of a global variable inside of your web application. 1005 00:53:25,450 --> 00:53:29,920 And to do that, we can connect Flask with databases using SQL in order 1006 00:53:29,920 --> 00:53:34,210 to be able to run SQL queries in order to select data or insert data or update 1007 00:53:34,210 --> 00:53:37,810 data inside of our Flask web application itself so that users 1008 00:53:37,810 --> 00:53:41,110 can interact with that data on the pages that they visit. 1009 00:53:41,110 --> 00:53:42,610 But this is the power of Flask. 1010 00:53:42,610 --> 00:53:45,220 The ability to build these dynamic web applications that 1011 00:53:45,220 --> 00:53:48,370 are able to listen for requests and respond with dynamically 1012 00:53:48,370 --> 00:53:51,100 generated HTML, which give us the power to create 1013 00:53:51,100 --> 00:53:53,440 all the more interesting and more expressive 1014 00:53:53,440 --> 00:53:56,190 web applications on the internet. 1015 00:53:56,190 --> 00:53:57,000