1 00:00:00,000 --> 00:00:30,195 [MUSIC PLAYING] 2 00:00:30,195 --> 00:00:49,570 3 00:00:49,570 --> 00:00:53,200 DAVID J. MALAN: All right, this is CS50, and this is week nine, 4 00:00:53,200 --> 00:00:55,510 the week where we synthesize the past several weeks 5 00:00:55,510 --> 00:00:59,440 and the past several languages, including HTML, CSS, and JavaScript 6 00:00:59,440 --> 00:01:02,680 most recently, plus some SQL, plus some Python. 7 00:01:02,680 --> 00:01:05,890 Indeed, the goal for this week is to synthesize all of those materials 8 00:01:05,890 --> 00:01:08,890 into a topic that's broadly described as web programming. 9 00:01:08,890 --> 00:01:11,530 Now to be fair, last week we did introduce a bit of JavaScript, 10 00:01:11,530 --> 00:01:13,570 and via JavaScript can you indeed program, 11 00:01:13,570 --> 00:01:16,750 but it was entirely client side as we used JavaScript last week. 12 00:01:16,750 --> 00:01:19,780 This week we'll reintroduce a server side component 13 00:01:19,780 --> 00:01:23,500 and indeed end by tying together the browser, the so-called client, 14 00:01:23,500 --> 00:01:27,380 and the web server, the backend of any web application. 15 00:01:27,380 --> 00:01:29,770 So to get there, let's consider where we came from. 16 00:01:29,770 --> 00:01:34,060 Last week in order to serve up any of your static web pages, 17 00:01:34,060 --> 00:01:37,330 static in the sense that once you write them, they don't change 18 00:01:37,330 --> 00:01:39,880 fundamentally, they don't particularly take user input 19 00:01:39,880 --> 00:01:41,770 unless you add a little bit of JavaScript, 20 00:01:41,770 --> 00:01:44,650 we use just this simple program called http-server. 21 00:01:44,650 --> 00:01:48,520 Now there are other equivalents of this command on Macs and Windows 22 00:01:48,520 --> 00:01:51,280 and Linux and other platforms, but for our purposes, 23 00:01:51,280 --> 00:01:55,900 http-server the program literally just runs a web server. 24 00:01:55,900 --> 00:01:57,880 And a web server is just a piece of software 25 00:01:57,880 --> 00:02:03,820 that's constantly listening on port 80 or port 443 in terms of TCP recall, 26 00:02:03,820 --> 00:02:05,530 and it's just listening for connections. 27 00:02:05,530 --> 00:02:08,889 And any time your browser connects it looks at the URL 28 00:02:08,889 --> 00:02:11,470 that you visited and maybe some parameters that you 29 00:02:11,470 --> 00:02:15,220 may have provided via that URL, or more generally via a form, 30 00:02:15,220 --> 00:02:19,390 and it then serves up a web page, optionally with some kind of output. 31 00:02:19,390 --> 00:02:22,510 But of course everything last week really was just static. 32 00:02:22,510 --> 00:02:25,360 It was just HTML files, CSS files, and maybe 33 00:02:25,360 --> 00:02:27,820 some JavaScript files or JavaScript within. 34 00:02:27,820 --> 00:02:30,520 But within the requests that your browsers 35 00:02:30,520 --> 00:02:35,880 were sending to that web server, were recall HTTP headers like this. 36 00:02:35,880 --> 00:02:39,640 And so among the things that program http-server was doing, 37 00:02:39,640 --> 00:02:41,980 and among the things any web server was doing, 38 00:02:41,980 --> 00:02:45,950 was analyzing the contents of that virtual envelope, top to bottom, 39 00:02:45,950 --> 00:02:49,627 left to right, trying to understand what is it your browser or your friend 40 00:02:49,627 --> 00:02:51,460 or your family member if you shared your you 41 00:02:51,460 --> 00:02:53,620 URL with them was trying to request. 42 00:02:53,620 --> 00:02:57,130 And if the first line of those HTTP headers was just get slash, 43 00:02:57,130 --> 00:02:59,240 that just means give me the default web page. 44 00:02:59,240 --> 00:03:03,730 And by convention, recall that typically means specifically give me the file 45 00:03:03,730 --> 00:03:05,470 called index dot HTML. 46 00:03:05,470 --> 00:03:08,380 That might have been explicit if you literally typed index 47 00:03:08,380 --> 00:03:12,760 dot HTML into the browser's URL bar, that would even more explicitly tell 48 00:03:12,760 --> 00:03:14,800 the server to give you that file. 49 00:03:14,800 --> 00:03:18,286 But recall we also played with google.com 50 00:03:18,286 --> 00:03:20,680 and specifically its search functionality. 51 00:03:20,680 --> 00:03:23,590 And recall that we manually last week constructed 52 00:03:23,590 --> 00:03:26,230 a URL that looked like this, and then we replicated it 53 00:03:26,230 --> 00:03:30,520 with an actual HTML form, the result of which when submitting it brought us 54 00:03:30,520 --> 00:03:37,000 to a URL of the form HTTPS colon slash slash, www.google.com slash search, 55 00:03:37,000 --> 00:03:39,670 question mark q equals cats. 56 00:03:39,670 --> 00:03:43,300 And last week http-server is fairly simplistic. 57 00:03:43,300 --> 00:03:44,870 It only served static content. 58 00:03:44,870 --> 00:03:48,370 So it was pretty much ignoring things like these URL parameters. 59 00:03:48,370 --> 00:03:51,910 But if you actually want to write a backend web server, 60 00:03:51,910 --> 00:03:54,880 a web application like google.com itself, you 61 00:03:54,880 --> 00:03:58,210 need to be able to analyze the contents of this virtual envelope, 62 00:03:58,210 --> 00:04:02,080 figure out what path the user wants, or route, so to speak. 63 00:04:02,080 --> 00:04:04,840 Slash search would be the route here in question. 64 00:04:04,840 --> 00:04:08,380 And then you have to figure out what the exact HTTP parameters are. 65 00:04:08,380 --> 00:04:11,110 Q, in this case, whose value is "cats." 66 00:04:11,110 --> 00:04:16,360 So someone somewhere has to write code that parses that string, figuring out 67 00:04:16,360 --> 00:04:19,360 that you want slash search and then, OK, let's ignore the question mark. 68 00:04:19,360 --> 00:04:22,660 Let's declare a variable called q, and let's give it a value of "cats." 69 00:04:22,660 --> 00:04:26,050 Like somewhere in the picture there needs to be code that does that. 70 00:04:26,050 --> 00:04:28,510 And today we introduce you to that very code. 71 00:04:28,510 --> 00:04:31,810 And we're going to introduce you to a library called Flask. 72 00:04:31,810 --> 00:04:35,080 And technically speaking, Flask is also called a framework. 73 00:04:35,080 --> 00:04:37,700 A framework is a way of doing things. 74 00:04:37,700 --> 00:04:40,420 It's a way of organizing your code, it's a way 75 00:04:40,420 --> 00:04:42,790 of writing your code that more specifically is 76 00:04:42,790 --> 00:04:44,500 just how you should use this library. 77 00:04:44,500 --> 00:04:45,730 Now why does Flask exist? 78 00:04:45,730 --> 00:04:47,200 And there are alternatives. 79 00:04:47,200 --> 00:04:50,860 Well, Flask exists just to honestly simplify a lot of tasks 80 00:04:50,860 --> 00:04:54,170 that for you and me would just get pretty boring pretty quickly. 81 00:04:54,170 --> 00:04:56,500 Imagine how annoying it would be if you wanted 82 00:04:56,500 --> 00:05:00,130 to implement some new website or some new mobile application for that matter, 83 00:05:00,130 --> 00:05:05,380 and you had to write code that analyzed text like this every time 84 00:05:05,380 --> 00:05:07,540 just to figure out what the user's input is. 85 00:05:07,540 --> 00:05:10,510 Wouldn't it be nice if you can just call a function, the equivalent 86 00:05:10,510 --> 00:05:14,320 of get string or get int, and let some other function written 87 00:05:14,320 --> 00:05:17,860 by someone else look at that text, figure out what the parameters are 88 00:05:17,860 --> 00:05:22,180 and what their values are, and just hand them to you in nice easy to use 89 00:05:22,180 --> 00:05:23,030 variables. 90 00:05:23,030 --> 00:05:25,580 So that is one of the things that Flask does for you. 91 00:05:25,580 --> 00:05:28,330 It analyzes the insides of these virtual envelopes, 92 00:05:28,330 --> 00:05:31,660 figures out what the user input is, figures out 93 00:05:31,660 --> 00:05:35,500 what the route is, like slash search or slash index dot HTML 94 00:05:35,500 --> 00:05:38,260 that the user wants, and makes it more easily 95 00:05:38,260 --> 00:05:40,240 available to you, the programmer. 96 00:05:40,240 --> 00:05:43,330 And it's a framework now in the sense that typically when 97 00:05:43,330 --> 00:05:48,300 you create, as we will today, a Flask based web application, 98 00:05:48,300 --> 00:05:51,453 you're going to typically organize your files and folders in this way. 99 00:05:51,453 --> 00:05:52,995 And this is what I mean by framework. 100 00:05:52,995 --> 00:05:56,610 Frameworks are not just libraries where they have functions that you can call. 101 00:05:56,610 --> 00:06:00,460 They typically have documentation that says, to use these functions, 102 00:06:00,460 --> 00:06:04,200 you should additionally organize your files and folders in this way. 103 00:06:04,200 --> 00:06:08,460 And perhaps the simplest Flask application would have these files: 104 00:06:08,460 --> 00:06:13,680 application dot py, which is where really all of our effort 105 00:06:13,680 --> 00:06:16,350 is going to go in writing code, in this case in Python, 106 00:06:16,350 --> 00:06:20,670 requirements dot text, which is just a simple text file that enumerates, 107 00:06:20,670 --> 00:06:24,300 top to bottom, one per line, what are the other libraries that you 108 00:06:24,300 --> 00:06:27,112 want to use in your application, static, which 109 00:06:27,112 --> 00:06:29,070 is going to be a folder that literally contains 110 00:06:29,070 --> 00:06:33,060 static files like your gifs, your jpegs, your pings, your CSS 111 00:06:33,060 --> 00:06:36,720 files, your JavaScript files, any of the files you wrote this past week, 112 00:06:36,720 --> 00:06:40,650 now they're going to go into this static folder, and lastly templates. 113 00:06:40,650 --> 00:06:44,070 And templates is going to be where more of your HTML goes. 114 00:06:44,070 --> 00:06:47,770 And we'll see what the distinction is there versus last week. 115 00:06:47,770 --> 00:06:50,160 So in short if you want to make a web application, 116 00:06:50,160 --> 00:06:53,160 not a website, a web application that takes user input, 117 00:06:53,160 --> 00:06:55,380 produces user output, maybe talks to a database, 118 00:06:55,380 --> 00:06:58,260 maybe sends emails, maybe does any number of other things, 119 00:06:58,260 --> 00:07:01,680 programmatically you have a web application 120 00:07:01,680 --> 00:07:04,380 and will use this framework here called Flask. 121 00:07:04,380 --> 00:07:05,550 And there are alternatives. 122 00:07:05,550 --> 00:07:09,300 In the world of Python there is a framework called Django, 123 00:07:09,300 --> 00:07:13,380 in the world of PHP there are frameworks like Symfony and Laravel and the like. 124 00:07:13,380 --> 00:07:17,260 In Java, in C sharp, and other languages there are similar frameworks. 125 00:07:17,260 --> 00:07:21,490 So this is just representative of the types of frameworks that are out there. 126 00:07:21,490 --> 00:07:25,320 But it's perhaps helpful to know before we dive into some actual code 127 00:07:25,320 --> 00:07:29,490 that these frameworks tend to implement certain design patterns. 128 00:07:29,490 --> 00:07:32,970 A design pattern is, again, just a fancy way of describing ways 129 00:07:32,970 --> 00:07:34,650 that humans write code. 130 00:07:34,650 --> 00:07:36,870 Suffice it to say over the past many decades, 131 00:07:36,870 --> 00:07:39,510 a lot of humans working initially independently 132 00:07:39,510 --> 00:07:41,670 kept solving the same problems again and again, 133 00:07:41,670 --> 00:07:44,160 and they realized, wow, I'm noticing patterns 134 00:07:44,160 --> 00:07:46,290 in how I'm solving a problem for this project 135 00:07:46,290 --> 00:07:47,980 and for this project and another. 136 00:07:47,980 --> 00:07:50,380 And once human programmers noticed these patterns, 137 00:07:50,380 --> 00:07:53,100 they might formalize them by writing a book, 138 00:07:53,100 --> 00:07:55,080 by writing a blog post or the like, and then 139 00:07:55,080 --> 00:07:58,750 give them a name, a design pattern that they recommend that other people adopt. 140 00:07:58,750 --> 00:07:59,340 Why? 141 00:07:59,340 --> 00:08:02,250 Just because it helps you organize your code instead 142 00:08:02,250 --> 00:08:04,530 of putting all your code in one massive file, 143 00:08:04,530 --> 00:08:07,260 well maybe if we put some code here, some code here, 144 00:08:07,260 --> 00:08:09,330 we can collaborate more effectively with others 145 00:08:09,330 --> 00:08:12,870 and just keep ourselves sane when maintaining bigger and bigger projects. 146 00:08:12,870 --> 00:08:15,210 So Flask implements what's generally known 147 00:08:15,210 --> 00:08:19,500 as an MVC design pattern or paradigm. 148 00:08:19,500 --> 00:08:23,730 MVC just refers to an acronym representing model, view, 149 00:08:23,730 --> 00:08:24,630 and controller. 150 00:08:24,630 --> 00:08:27,900 And these are sort of technical terms of art that at the end of the day 151 00:08:27,900 --> 00:08:29,730 we'll see are relatively simple. 152 00:08:29,730 --> 00:08:33,539 Controller is going to be where you write most of your Python code. 153 00:08:33,539 --> 00:08:37,390 It is the file or files that control your web application. 154 00:08:37,390 --> 00:08:41,250 So in the past, any time we've written a C program or a Python program, 155 00:08:41,250 --> 00:08:43,530 you have in effect been writing controller code. 156 00:08:43,530 --> 00:08:45,720 We just never slapped that label on it. 157 00:08:45,720 --> 00:08:50,760 There's also going to be today what we'll call a view, the V in MVC. 158 00:08:50,760 --> 00:08:55,710 And view just refers to all of the stuff that a human views, the HTML, the CSS, 159 00:08:55,710 --> 00:08:57,540 more generally the user interface. 160 00:08:57,540 --> 00:09:00,270 Anything involving the user is going to be described 161 00:09:00,270 --> 00:09:02,340 as part of your application's view. 162 00:09:02,340 --> 00:09:05,160 But again, any of the code that you, the programmer, write, 163 00:09:05,160 --> 00:09:07,620 that's part of your controller, so to speak. 164 00:09:07,620 --> 00:09:10,830 And then lastly is the so-called model, the M in MVC. 165 00:09:10,830 --> 00:09:15,930 And this generally refers to what technique, what service, what software 166 00:09:15,930 --> 00:09:17,590 you're using for your data. 167 00:09:17,590 --> 00:09:20,940 So maybe that's a SQL database, maybe that's a CSV file. 168 00:09:20,940 --> 00:09:24,330 The model refers to the data that your application is using. 169 00:09:24,330 --> 00:09:27,570 So again, none of these terms are introducing 170 00:09:27,570 --> 00:09:30,930 things we couldn't have done last week or in weeks prior. 171 00:09:30,930 --> 00:09:34,890 All we're doing by introducing MVC as an acronym or a design pattern 172 00:09:34,890 --> 00:09:38,760 is just to slap a label on the approach that Flask, 173 00:09:38,760 --> 00:09:40,710 and in turn many programmers, whether you're 174 00:09:40,710 --> 00:09:44,850 using Python or other languages used when designing web based applications. 175 00:09:44,850 --> 00:09:48,210 There are alternatives but this is among the most popular and perhaps 176 00:09:48,210 --> 00:09:49,350 among the simplest. 177 00:09:49,350 --> 00:09:51,360 So much like we've done with any language, 178 00:09:51,360 --> 00:09:53,550 let's take a look at the simplest possible web 179 00:09:53,550 --> 00:09:57,930 application you might write using this library or framework called Flask. 180 00:09:57,930 --> 00:10:01,830 It turns out if you fill a file called application dot py 181 00:10:01,830 --> 00:10:06,697 with these lines of code, you have just made your very first web application. 182 00:10:06,697 --> 00:10:09,030 Now it's not going to do much of interest, as we'll see, 183 00:10:09,030 --> 00:10:12,720 but this is the minimal amount of code pretty much that you need in order 184 00:10:12,720 --> 00:10:16,470 to write a web application that is a program that once you start 185 00:10:16,470 --> 00:10:20,400 it is going to just be constantly listening and listening and listening 186 00:10:20,400 --> 00:10:26,310 for TCP requests on port 80 or 443 to come in from people's browsers, 187 00:10:26,310 --> 00:10:27,450 your own included. 188 00:10:27,450 --> 00:10:30,870 And then now you have the ability to write 189 00:10:30,870 --> 00:10:33,760 code that responds to those users. 190 00:10:33,760 --> 00:10:34,928 So what do I mean by this? 191 00:10:34,928 --> 00:10:36,720 Well, let's go ahead and see this in action 192 00:10:36,720 --> 00:10:39,990 and start writing some of our own very first programs. 193 00:10:39,990 --> 00:10:43,230 I'm going to switch over to CS50 IDE, which we'll continue using here. 194 00:10:43,230 --> 00:10:45,460 I'm not going to run http-server anymore. 195 00:10:45,460 --> 00:10:48,850 Instead we're going to use Flask which will take the place of that server. 196 00:10:48,850 --> 00:10:52,190 And I'm going to go ahead and let's create a very simple file first. 197 00:10:52,190 --> 00:10:54,507 I'm going to go ahead and, actually let's do this. 198 00:10:54,507 --> 00:10:56,090 I'm going to first create a directory. 199 00:10:56,090 --> 00:10:58,120 So I'm going to create a directory called Hello, 200 00:10:58,120 --> 00:10:59,750 and I'm going to cd into Hello. 201 00:10:59,750 --> 00:11:01,750 And as always, if you open your file browser 202 00:11:01,750 --> 00:11:04,570 you'll see the same thing at top left, but in general I'll 203 00:11:04,570 --> 00:11:05,860 focus on the command line. 204 00:11:05,860 --> 00:11:09,550 And now that I'm in the Hello directory, let me go ahead and create a file. 205 00:11:09,550 --> 00:11:13,375 And I'll save this in Hello, whoops, I'll save this in Hello. 206 00:11:13,375 --> 00:11:15,940 207 00:11:15,940 --> 00:11:20,050 And let me go ahead and call this, let's say, 208 00:11:20,050 --> 00:11:24,400 application dot py, and again, saving it in the Hello directory. 209 00:11:24,400 --> 00:11:27,530 All right if I type ls, I'll see it there and it's currently empty. 210 00:11:27,530 --> 00:11:30,910 So let me go ahead and pretty much copy some of that code from a moment ago. 211 00:11:30,910 --> 00:11:34,270 Let me go ahead and from the Flask library import something 212 00:11:34,270 --> 00:11:37,930 called Flask, capital F in this case, which is just their convention. 213 00:11:37,930 --> 00:11:43,390 And let me go ahead and also import something called render. 214 00:11:43,390 --> 00:11:45,110 Actually let's not even do that yet. 215 00:11:45,110 --> 00:11:46,960 Let's keep this minimalist at first. 216 00:11:46,960 --> 00:11:51,250 In order to turn this file into a full-fledged Flask application that 217 00:11:51,250 --> 00:11:54,370 is my own server, I'm going to go ahead and define a variable called 218 00:11:54,370 --> 00:11:55,840 app by convention. 219 00:11:55,840 --> 00:11:58,180 I'm going to call this Flask function, and I'm 220 00:11:58,180 --> 00:12:01,180 a little weirdly going to pass an underscore, underscore, name, 221 00:12:01,180 --> 00:12:02,500 underscore, underscore. 222 00:12:02,500 --> 00:12:05,710 Now we've only seen that special variable once in the past. 223 00:12:05,710 --> 00:12:08,410 And that, recall, was when I said, well, you should either 224 00:12:08,410 --> 00:12:12,310 call main at the bottom of your Python file to call your main function, 225 00:12:12,310 --> 00:12:15,700 or you can do this annoying thing where you say, if name equals, 226 00:12:15,700 --> 00:12:17,800 equals main then call main. 227 00:12:17,800 --> 00:12:22,180 So no matter why we used that in the past, this special variable, 228 00:12:22,180 --> 00:12:25,360 underscore, underscore, name, underscore, underscore essentially 229 00:12:25,360 --> 00:12:27,890 refers to the name of the current file. 230 00:12:27,890 --> 00:12:32,050 So this is a line of code that says, Flask, turn the current file 231 00:12:32,050 --> 00:12:35,500 into an application, that is a web application that 232 00:12:35,500 --> 00:12:37,420 will listen for browsers' requests. 233 00:12:37,420 --> 00:12:41,650 Now in my file I have to tell Flask what are my routes. 234 00:12:41,650 --> 00:12:43,810 A route is simply a URL. 235 00:12:43,810 --> 00:12:48,174 So slash, or slash index dot HTML, or slash 236 00:12:48,174 --> 00:12:52,870 search, or any number of other paths that you see in today's URLs 237 00:12:52,870 --> 00:12:53,680 on websites. 238 00:12:53,680 --> 00:12:57,810 And to do this in Flask I say app dot route, quote unquote slash. 239 00:12:57,810 --> 00:13:00,970 Now, this is something we've not seen in Python before, 240 00:13:00,970 --> 00:13:02,620 but this is actually a Python feature. 241 00:13:02,620 --> 00:13:05,740 Any time you see an at sign at the beginning of a function like this, 242 00:13:05,740 --> 00:13:07,600 it's what's called a Python decorator. 243 00:13:07,600 --> 00:13:11,500 And for our purposes today, this is just a special way 244 00:13:11,500 --> 00:13:14,020 of applying one function to another. 245 00:13:14,020 --> 00:13:16,090 But let me leave it at that for now and just 246 00:13:16,090 --> 00:13:19,420 say that the convention when using Flask is that at first you 247 00:13:19,420 --> 00:13:22,460 define your route like your slash default route, 248 00:13:22,460 --> 00:13:23,780 then you define a function. 249 00:13:23,780 --> 00:13:25,870 And the function can be called whatever you want, 250 00:13:25,870 --> 00:13:27,820 but by convention you should probably call 251 00:13:27,820 --> 00:13:31,720 it something appropriate for the actual route in question. 252 00:13:31,720 --> 00:13:34,330 And again, humans tend to call the default route your index. 253 00:13:34,330 --> 00:13:36,580 So I'm going to go ahead and call this function index. 254 00:13:36,580 --> 00:13:40,780 And below that, let me just go ahead and do something silly like Hello, world, 255 00:13:40,780 --> 00:13:43,060 literally returning that string. 256 00:13:43,060 --> 00:13:46,990 And let's go ahead and see what exactly happens here after doing that. 257 00:13:46,990 --> 00:13:50,650 Let me go ahead now and in my Hello directory if I type ls, 258 00:13:50,650 --> 00:13:53,920 notice that again, I only have one file, application dot py. 259 00:13:53,920 --> 00:13:57,370 In order to start my server today, because it's a Flask application, 260 00:13:57,370 --> 00:14:00,370 I do not want to use http-server, I instead 261 00:14:00,370 --> 00:14:02,440 want to run the command Flask run. 262 00:14:02,440 --> 00:14:04,390 So Flask is, yes, a library. 263 00:14:04,390 --> 00:14:06,910 But it also comes with a program when you install it 264 00:14:06,910 --> 00:14:11,870 on your Mac or PC or the IDE that lets you start a Flask application as well. 265 00:14:11,870 --> 00:14:13,850 And you'll see some cryptic output here. 266 00:14:13,850 --> 00:14:16,960 But just like http-server, you'll see the URL 267 00:14:16,960 --> 00:14:19,130 of your currently running application. 268 00:14:19,130 --> 00:14:23,500 And if I go ahead and click this URL and open it in another tab, voila, 269 00:14:23,500 --> 00:14:27,250 I see my very first dynamic web application. 270 00:14:27,250 --> 00:14:28,990 It's only printing Hello, world. 271 00:14:28,990 --> 00:14:33,530 And in fact, if I go to Chrome's view page source feature, 272 00:14:33,530 --> 00:14:35,740 notice that it's not even full-fledged HTML. 273 00:14:35,740 --> 00:14:38,050 It's literally text, but that's because I didn't 274 00:14:38,050 --> 00:14:41,710 bother returning any actual HTML yet. 275 00:14:41,710 --> 00:14:42,880 So let's do that. 276 00:14:42,880 --> 00:14:45,310 Let's actually do this more properly and not just return 277 00:14:45,310 --> 00:14:47,110 some arbitrary string of text. 278 00:14:47,110 --> 00:14:51,490 Let me stop the server and let me focus now on doing this. 279 00:14:51,490 --> 00:14:54,640 By default the route called slash I've claimed 280 00:14:54,640 --> 00:14:58,330 means that you should return a file called index dot HTML. 281 00:14:58,330 --> 00:15:00,530 Well let's assume for the moment it exists. 282 00:15:00,530 --> 00:15:02,140 How do I go ahead and return it? 283 00:15:02,140 --> 00:15:04,030 Technically I'm going to go ahead and render 284 00:15:04,030 --> 00:15:07,240 a template called index dot HTML. 285 00:15:07,240 --> 00:15:09,700 And in order to use this function render template, 286 00:15:09,700 --> 00:15:13,370 I need to import it from the Flask library as well. 287 00:15:13,370 --> 00:15:16,100 So Flask again is a library, comes with a lot of functions. 288 00:15:16,100 --> 00:15:18,080 The first one of which is called Flask itself. 289 00:15:18,080 --> 00:15:20,710 That's what activates this as a web application. 290 00:15:20,710 --> 00:15:23,410 Render template is another function whose purpose in life 291 00:15:23,410 --> 00:15:28,490 is to go find a file called index dot HTML, grab its contents, 292 00:15:28,490 --> 00:15:29,860 so that you can then return it. 293 00:15:29,860 --> 00:15:35,860 So it's similar in spirit to using open and read in Python a few weeks ago. 294 00:15:35,860 --> 00:15:38,470 But it's going to give us some other fancy features as well. 295 00:15:38,470 --> 00:15:40,600 But let me go now into my command line, type 296 00:15:40,600 --> 00:15:43,330 ls to remind us that we only have application dot py. 297 00:15:43,330 --> 00:15:46,330 I don't want to create index dot HTML in the same directory. 298 00:15:46,330 --> 00:15:50,110 Flask, recall, has certain organizational recommendations 299 00:15:50,110 --> 00:15:54,040 like this here whereby I should actually put index dot 300 00:15:54,040 --> 00:15:59,510 HTML and all of my HTML files today onward in my folder called templates. 301 00:15:59,510 --> 00:16:00,290 So let's do that. 302 00:16:00,290 --> 00:16:04,300 Let me go ahead and make a directory called templates with make dir enter. 303 00:16:04,300 --> 00:16:07,390 If I type ls now you'll see that I have a templates directory. 304 00:16:07,390 --> 00:16:11,740 Now let me go ahead and create a new actual file called index dot HTML. 305 00:16:11,740 --> 00:16:15,400 Let me store that in my templates, directory and now let me go ahead 306 00:16:15,400 --> 00:16:17,290 and something pretty familiar. 307 00:16:17,290 --> 00:16:20,180 We've done this many times at this point whereby we just 308 00:16:20,180 --> 00:16:22,110 whip up a quick HTML page. 309 00:16:22,110 --> 00:16:24,740 I'll give my doc type of HTML up here. 310 00:16:24,740 --> 00:16:26,360 Let me have my HTML tag. 311 00:16:26,360 --> 00:16:29,960 My language will be English by default. Down here I'm 312 00:16:29,960 --> 00:16:31,580 going to have the head of my page. 313 00:16:31,580 --> 00:16:33,640 Inside the head I'll have a title. 314 00:16:33,640 --> 00:16:34,880 I'm going to call this Hello. 315 00:16:34,880 --> 00:16:36,350 Down here I'll have my body. 316 00:16:36,350 --> 00:16:40,340 Inside the body I'm just going to say Hello, world instead. 317 00:16:40,340 --> 00:16:43,760 So still no progress really from last week. 318 00:16:43,760 --> 00:16:46,790 But let me now go back to application dot py, 319 00:16:46,790 --> 00:16:50,900 remind us that we've just now returned the function call, 320 00:16:50,900 --> 00:16:54,650 render template of index dot HTML, and again, this function, render template, 321 00:16:54,650 --> 00:16:57,920 is going to go open that file, grab all of the bytes inside of it 322 00:16:57,920 --> 00:17:00,450 and return them ultimately via this line. 323 00:17:00,450 --> 00:17:03,950 So now let me go ahead and run Flask run again, let me go ahead 324 00:17:03,950 --> 00:17:07,730 and click on my IDE's URL, voila, same thing. 325 00:17:07,730 --> 00:17:11,760 But now if I open up Chrome's view source feature, 326 00:17:11,760 --> 00:17:15,680 notice now that I've returned a full-fledged web page. 327 00:17:15,680 --> 00:17:18,170 So again, not really fundamentally that interesting, 328 00:17:18,170 --> 00:17:23,030 but I've taken this baby step now toward generating any HTML that I want. 329 00:17:23,030 --> 00:17:24,530 So let's make this more interesting. 330 00:17:24,530 --> 00:17:28,310 I've claimed all along that there is this way of course with web programming 331 00:17:28,310 --> 00:17:32,000 to take user input via the URL. 332 00:17:32,000 --> 00:17:33,690 So how can we go about doing that? 333 00:17:33,690 --> 00:17:35,810 Well, me go ahead and propose this. 334 00:17:35,810 --> 00:17:39,620 Let me go ahead here and write an additional line of code 335 00:17:39,620 --> 00:17:41,390 that does something like this. 336 00:17:41,390 --> 00:17:45,770 Let me declare a variable called, actually let's do this. 337 00:17:45,770 --> 00:17:51,200 After render template, it turns out you can pass in 0 or more named arguments. 338 00:17:51,200 --> 00:17:53,840 And the names of these arguments are entirely up to you, 339 00:17:53,840 --> 00:17:55,310 and we haven't seen that thus far. 340 00:17:55,310 --> 00:17:58,130 Thus far in the past, any time we've used someone else's function, 341 00:17:58,130 --> 00:18:00,422 you had to check the documentation or the lecture notes 342 00:18:00,422 --> 00:18:02,840 to figure out what were the available arguments you 343 00:18:02,840 --> 00:18:04,342 could pass into this function. 344 00:18:04,342 --> 00:18:06,050 But that's not true with render template. 345 00:18:06,050 --> 00:18:07,380 It's a little more powerful. 346 00:18:07,380 --> 00:18:13,370 So if I want to pass a user's name from my application dot py file, 347 00:18:13,370 --> 00:18:16,020 which, recall we're going to start calling my controller, 348 00:18:16,020 --> 00:18:18,230 I can say, give me a variable called name. 349 00:18:18,230 --> 00:18:21,200 What do I want the value of this person's name to be? 350 00:18:21,200 --> 00:18:24,920 Well really what I want it to be is the equivalent 351 00:18:24,920 --> 00:18:27,380 of whatever is after that question mark, right? 352 00:18:27,380 --> 00:18:31,340 The only way, fundamentally, to get user input from a URL, we've seen, 353 00:18:31,340 --> 00:18:32,990 is whatever is after the question mark. 354 00:18:32,990 --> 00:18:35,150 And I don't want q, and I don't want cats, 355 00:18:35,150 --> 00:18:38,930 I want name equals David or name equals Brian. 356 00:18:38,930 --> 00:18:40,320 So how can I do that? 357 00:18:40,320 --> 00:18:43,250 Well, let me go ahead and say this: name equals 358 00:18:43,250 --> 00:18:48,320 request dot args dot get, quote unquote name, 359 00:18:48,320 --> 00:18:52,050 and let me Additionally add request to the top of this file. 360 00:18:52,050 --> 00:18:53,120 So what am I doing? 361 00:18:53,120 --> 00:18:58,040 When I import this other request variable from the Flask library, 362 00:18:58,040 --> 00:19:03,920 this gives me access to the HTTP request and with it any parameters 363 00:19:03,920 --> 00:19:06,020 that might have been in the URL. 364 00:19:06,020 --> 00:19:09,200 And what Flask does for me is it parses that URL. 365 00:19:09,200 --> 00:19:12,530 It figures out what is q, what is cats, what is name, what is David. 366 00:19:12,530 --> 00:19:16,190 Whatever is after the question mark, Flask parses it for me 367 00:19:16,190 --> 00:19:19,940 and hands it back to me as variables, and I can get access to those variables 368 00:19:19,940 --> 00:19:22,910 by calling request dot args for arguments, 369 00:19:22,910 --> 00:19:26,330 dot get, and then the name of the parameter 370 00:19:26,330 --> 00:19:29,900 that I want to get from the URL. 371 00:19:29,900 --> 00:19:35,750 So now if I save this, let me go back to index dot HTML, 372 00:19:35,750 --> 00:19:40,610 and here is why this file today onward is now called a template. 373 00:19:40,610 --> 00:19:43,400 A template, just like in the human world, 374 00:19:43,400 --> 00:19:46,400 is kind of a framework into which you can plug other values. 375 00:19:46,400 --> 00:19:48,530 It's a template that you can base your own work on. 376 00:19:48,530 --> 00:19:51,270 It's like a blueprint that you can base a building on. 377 00:19:51,270 --> 00:19:54,230 So templates typically have special syntax 378 00:19:54,230 --> 00:19:56,090 via which you can plug in some values. 379 00:19:56,090 --> 00:19:59,930 And I'm afraid the syntax is slightly new versus past things we've seen, 380 00:19:59,930 --> 00:20:03,140 but if you use two curly braces, as though one weren't 381 00:20:03,140 --> 00:20:08,090 bad enough in C and in other contexts, two curly braces, left and right, 382 00:20:08,090 --> 00:20:13,070 you can tell Flask's render template function to plug 383 00:20:13,070 --> 00:20:16,070 in right there the value of any variable that you 384 00:20:16,070 --> 00:20:21,020 have passed into render template as one of these arguments in the function 385 00:20:21,020 --> 00:20:22,050 call. 386 00:20:22,050 --> 00:20:25,610 So let me go ahead now and run Flask run again to restart my web server. 387 00:20:25,610 --> 00:20:29,330 Let me go ahead and open this URL, and it looks pretty stupid right now. 388 00:20:29,330 --> 00:20:30,530 Hello, None. 389 00:20:30,530 --> 00:20:33,020 But recall that None is a special value in Python. 390 00:20:33,020 --> 00:20:35,190 It means something has no value. 391 00:20:35,190 --> 00:20:36,960 So you know what I could do? 392 00:20:36,960 --> 00:20:42,176 It turns out that, let me go back over here, if I go back to my URL, 393 00:20:42,176 --> 00:20:45,134 and let me zoom out so you can see it, let me go ahead and add a slash, 394 00:20:45,134 --> 00:20:49,130 question mark, and not q equals cats because that's irrelevant now, 395 00:20:49,130 --> 00:20:51,740 but how about name equals David. 396 00:20:51,740 --> 00:20:52,940 And let me zoom in on that. 397 00:20:52,940 --> 00:20:56,630 All I've added is the slash question mark name equals David. 398 00:20:56,630 --> 00:20:59,660 Let me go ahead and hit Enter, and voila, now I 399 00:20:59,660 --> 00:21:01,370 have a web page that says Hello David. 400 00:21:01,370 --> 00:21:04,580 And indeed if I view my page source, notice the HTML 401 00:21:04,580 --> 00:21:06,200 has been dynamically generated. 402 00:21:06,200 --> 00:21:09,650 There is no file on my IDE that says Hello comma David, 403 00:21:09,650 --> 00:21:11,600 rather it's been dynamically plugged in. 404 00:21:11,600 --> 00:21:12,830 And notice this can change. 405 00:21:12,830 --> 00:21:15,830 If I go ahead and change the name to Brian, enter, 406 00:21:15,830 --> 00:21:18,470 his page changes, and of course if I view the page source now 407 00:21:18,470 --> 00:21:21,410 it's as though I had a file called index dot HTML 408 00:21:21,410 --> 00:21:23,300 that literally had Brian's name in it. 409 00:21:23,300 --> 00:21:27,560 But no, there's just that placeholder within my template instead. 410 00:21:27,560 --> 00:21:28,670 And I can clean this up. 411 00:21:28,670 --> 00:21:32,000 Notice it looked pretty stupid if there was no value for name, 412 00:21:32,000 --> 00:21:34,420 but it turns out the request dot args, dot 413 00:21:34,420 --> 00:21:37,430 get function takes a second optional argument. 414 00:21:37,430 --> 00:21:40,220 If I don't know if there's going to be of value 415 00:21:40,220 --> 00:21:42,200 and I want to give it a default argument, 416 00:21:42,200 --> 00:21:46,800 my second argument to the get function can actually be the default value. 417 00:21:46,800 --> 00:21:50,390 So if I go ahead now, and let me go ahead rerun Flask. 418 00:21:50,390 --> 00:21:53,690 And let me go ahead now and reload with no name argument. 419 00:21:53,690 --> 00:21:57,500 Now you see a default value of Hello comma world, but if I go back up there 420 00:21:57,500 --> 00:22:00,680 and put my name back in, now it doesn't need the default. 421 00:22:00,680 --> 00:22:04,680 I see what the human actually typed in. 422 00:22:04,680 --> 00:22:06,800 So what's going on here, well, if you consider 423 00:22:06,800 --> 00:22:10,730 what google.com is doing when you type in cats and hit Enter, 424 00:22:10,730 --> 00:22:15,140 that word q equals cats is being passed to google.com in the URL, 425 00:22:15,140 --> 00:22:18,440 Google is running some program, maybe it's Python with Flask, 426 00:22:18,440 --> 00:22:21,230 maybe it's some other language that's analyzing the URL, 427 00:22:21,230 --> 00:22:25,040 grabbing q equals cats, and then they're searching their database essentially 428 00:22:25,040 --> 00:22:28,280 for a keyword of cats, and then they're dynamically 429 00:22:28,280 --> 00:22:31,700 generating the HTML that shows you all of those pictures and search 430 00:22:31,700 --> 00:22:33,260 results of cats. 431 00:22:33,260 --> 00:22:37,040 There is no web page, there's no HTML file on Google servers 432 00:22:37,040 --> 00:22:39,200 that constantly has a big list of cats. 433 00:22:39,200 --> 00:22:41,780 Like there's certainly no human maintaining a really big HTML 434 00:22:41,780 --> 00:22:45,410 file just filled with image tags and cats all day long. 435 00:22:45,410 --> 00:22:47,600 Suffice it to say that's all dynamically generated. 436 00:22:47,600 --> 00:22:50,330 And even with this trivial example, we see now 437 00:22:50,330 --> 00:22:54,620 perhaps that we're scratching the surface of that very capability. 438 00:22:54,620 --> 00:23:01,190 All right, let me pause here and see if there are any questions or confusion, 439 00:23:01,190 --> 00:23:04,070 because it's a lot all at once given that with any framework 440 00:23:04,070 --> 00:23:06,320 you typically have to learn the conventions first 441 00:23:06,320 --> 00:23:08,690 and then you can start to be productive. 442 00:23:08,690 --> 00:23:11,930 BRIAN: Yeah, so in your, when you called the render template function, 443 00:23:11,930 --> 00:23:16,100 someone asked why don't you need to say it's in templates slash index dot HTML, 444 00:23:16,100 --> 00:23:18,200 and why did you just say index dot HTML? 445 00:23:18,200 --> 00:23:18,900 DAVID J. MALAN: Good question. 446 00:23:18,900 --> 00:23:20,733 This is one of those "just because" answers. 447 00:23:20,733 --> 00:23:24,350 The render template function has been implemented in such a way 448 00:23:24,350 --> 00:23:27,770 that it assumes that your files are in the templates directory. 449 00:23:27,770 --> 00:23:30,650 You can technically override that by reconfiguring the application, 450 00:23:30,650 --> 00:23:32,480 but the default and indeed the convention 451 00:23:32,480 --> 00:23:35,060 is to just put those files in templates. 452 00:23:35,060 --> 00:23:36,170 Good question. 453 00:23:36,170 --> 00:23:37,220 Santiago? 454 00:23:37,220 --> 00:23:41,630 SANTIAGO: Why when you declare the app, app dot route, 455 00:23:41,630 --> 00:23:45,253 you have to include the forward slash as an argument to that? 456 00:23:45,253 --> 00:23:48,170 DAVID J. MALAN: Yeah, so why do you have to include the forward slash? 457 00:23:48,170 --> 00:23:52,220 That is the way, in Flask, of telling Flask, use 458 00:23:52,220 --> 00:23:54,590 the following function for this route. 459 00:23:54,590 --> 00:23:59,703 And slash is perhaps the simplest, certainly most basic route 460 00:23:59,703 --> 00:24:00,620 that you could define. 461 00:24:00,620 --> 00:24:02,570 It's sort of the absence of any other words. 462 00:24:02,570 --> 00:24:05,630 So you have to put slash there because otherwise the server won't 463 00:24:05,630 --> 00:24:11,390 know what to do if you visit something dot com, slash, and that's it. 464 00:24:11,390 --> 00:24:12,488 We can change this notice. 465 00:24:12,488 --> 00:24:14,030 I can change this to anything I want. 466 00:24:14,030 --> 00:24:18,170 Let me stop my server, and let me change this to slash secret, as though I'm 467 00:24:18,170 --> 00:24:20,540 creating a secret URL on my website. 468 00:24:20,540 --> 00:24:22,760 Let me go ahead and rerun Flask run. 469 00:24:22,760 --> 00:24:25,470 Let me open up this URL, and notice what happens. 470 00:24:25,470 --> 00:24:26,570 Nothing happens. 471 00:24:26,570 --> 00:24:29,510 Not found, 404 when I visit slash. 472 00:24:29,510 --> 00:24:31,160 And Chrome is just being annoying. 473 00:24:31,160 --> 00:24:34,010 It's hiding the slash just for simplicity these days, 474 00:24:34,010 --> 00:24:37,010 but the slash is there even though you're not seeing it as the human. 475 00:24:37,010 --> 00:24:42,380 But if I change this and go to slash secret, then we see that page again. 476 00:24:42,380 --> 00:24:46,430 So that app at app dot route function just 477 00:24:46,430 --> 00:24:52,513 lets you define what route should be associated with the following function. 478 00:24:52,513 --> 00:24:53,180 Other questions? 479 00:24:53,180 --> 00:24:55,160 Yeah, over to Sophia. 480 00:24:55,160 --> 00:24:58,070 SOPHIA: The model, is it a part of the HTML file now? 481 00:24:58,070 --> 00:25:02,218 Like the name, I guess as the data, is it encoded with an HTML file? 482 00:25:02,218 --> 00:25:04,010 DAVID J. MALAN: Yeah, at the moment I would 483 00:25:04,010 --> 00:25:05,930 argue we don't really have a model yet. 484 00:25:05,930 --> 00:25:07,980 Like there's no database, there's no CSV file, 485 00:25:07,980 --> 00:25:11,630 so right now we're just playing with C, controller and V, view. 486 00:25:11,630 --> 00:25:12,908 And that's totally fine. 487 00:25:12,908 --> 00:25:15,950 It's only when we have a full-fledged application like we soon will today 488 00:25:15,950 --> 00:25:18,120 that really the M comes into play. 489 00:25:18,120 --> 00:25:20,730 But again, this is sort of, reasonable people might disagree. 490 00:25:20,730 --> 00:25:23,780 They're just conventions, they're not hard, fast rules. 491 00:25:23,780 --> 00:25:27,470 All right, so this is a little silly, that in order 492 00:25:27,470 --> 00:25:31,130 to be greeted by my website you have to have the wherewithal 493 00:25:31,130 --> 00:25:35,510 to know that you have to type your own name into the URL bar, right? 494 00:25:35,510 --> 00:25:36,450 No one does that. 495 00:25:36,450 --> 00:25:38,930 That's just not how the web typically works. 496 00:25:38,930 --> 00:25:41,760 We instead find ourselves as humans filling out forms. 497 00:25:41,760 --> 00:25:45,260 So let's take this one step further and actually improve things in such a way 498 00:25:45,260 --> 00:25:47,760 that we actually have a form instead. 499 00:25:47,760 --> 00:25:49,200 So let me go ahead and do this. 500 00:25:49,200 --> 00:25:52,443 I'm going to go ahead and create another file. 501 00:25:52,443 --> 00:25:53,610 Let me go ahead and do this. 502 00:25:53,610 --> 00:25:56,780 Let me go into my templates directory where I currently 503 00:25:56,780 --> 00:26:00,200 only have index dot HTML, and let me just copy this file, 504 00:26:00,200 --> 00:26:04,400 index dot HTML, into another one right now called greet dot HTML. 505 00:26:04,400 --> 00:26:08,690 And that is to say I want my greet file, ultimately, let me go ahead 506 00:26:08,690 --> 00:26:12,020 and open this in my editor, greet ultimately 507 00:26:12,020 --> 00:26:14,970 is going to do the job that index was a moment ago. 508 00:26:14,970 --> 00:26:16,880 And I'm going to change the behavior of index 509 00:26:16,880 --> 00:26:19,500 dot HTML to instead have an actual form. 510 00:26:19,500 --> 00:26:21,500 So I'm going to go ahead and delete this and I'm 511 00:26:21,500 --> 00:26:24,560 going to do a form action equals, a route 512 00:26:24,560 --> 00:26:27,980 called slash greet, which doesn't exist yet, but I wager it soon will. 513 00:26:27,980 --> 00:26:31,160 I'll use get initially, and then inside of this form 514 00:26:31,160 --> 00:26:35,420 let me go ahead and give myself an input whose name is going to be literally 515 00:26:35,420 --> 00:26:37,190 name, because I want the human's name. 516 00:26:37,190 --> 00:26:40,430 So the red name is the tag's name. 517 00:26:40,430 --> 00:26:44,870 Name in green at the moment is the name of the human in question, 518 00:26:44,870 --> 00:26:46,730 although a little confusingly. 519 00:26:46,730 --> 00:26:50,270 And then let me go ahead and say the type of this field will be text. 520 00:26:50,270 --> 00:26:53,850 And then let me go ahead and give myself an input type, equals submit, 521 00:26:53,850 --> 00:26:57,560 so I have a submit button, and the value of that 522 00:26:57,560 --> 00:26:59,060 will be whatever the default is. 523 00:26:59,060 --> 00:27:02,240 So now let me go back to application dot py, 524 00:27:02,240 --> 00:27:04,400 let me go back to my Hello directory. 525 00:27:04,400 --> 00:27:07,220 Make sure you don't run Flask run in your templates directory. 526 00:27:07,220 --> 00:27:11,750 Make sure you only ever run it where the application dot py file is. 527 00:27:11,750 --> 00:27:13,660 Let me run this file. 528 00:27:13,660 --> 00:27:16,130 Let me go ahead and open it now, and voila. 529 00:27:16,130 --> 00:27:19,490 My slash route, the default route notice, 530 00:27:19,490 --> 00:27:21,930 has changed to be this HTML form. 531 00:27:21,930 --> 00:27:25,088 And if I look at the view source of that in Chrome, 532 00:27:25,088 --> 00:27:26,630 you'll see exactly what I just typed. 533 00:27:26,630 --> 00:27:28,380 So there's nothing dynamic about the form. 534 00:27:28,380 --> 00:27:29,540 That is indeed hard coded. 535 00:27:29,540 --> 00:27:31,170 There's no placeholders there. 536 00:27:31,170 --> 00:27:34,040 But notice that this form has been designed in advance by me to go 537 00:27:34,040 --> 00:27:36,980 to the slash greet route using get. 538 00:27:36,980 --> 00:27:38,360 Well how do I implement that? 539 00:27:38,360 --> 00:27:40,550 Well let me actually go into my application 540 00:27:40,550 --> 00:27:44,270 now, because you'll notice if I type in my name, David, and click Submit, 541 00:27:44,270 --> 00:27:45,140 not found. 542 00:27:45,140 --> 00:27:48,470 Because notice that slash greet does not exist. 543 00:27:48,470 --> 00:27:51,270 That is not a defined route in my application. 544 00:27:51,270 --> 00:27:56,420 So let me go back to my server, and let me go ahead down below, 545 00:27:56,420 --> 00:27:57,920 and let's just do something similar. 546 00:27:57,920 --> 00:28:01,260 App dot route, quote unquote, slash greet. 547 00:28:01,260 --> 00:28:02,927 So let's give myself a second route. 548 00:28:02,927 --> 00:28:04,760 Let me go ahead and define the function that 549 00:28:04,760 --> 00:28:07,040 should be called when a user visits slash greet. 550 00:28:07,040 --> 00:28:10,130 And again, you can call it anything you want, but let's keep ourselves, 551 00:28:10,130 --> 00:28:12,530 let's keep things simple and just call it the same thing 552 00:28:12,530 --> 00:28:14,990 as the route, though again, that's not a requirement. 553 00:28:14,990 --> 00:28:17,570 And then in my greet function, well what do I want to do? 554 00:28:17,570 --> 00:28:20,550 Let me go ahead and say, return "to do." 555 00:28:20,550 --> 00:28:21,780 I haven't done it yet. 556 00:28:21,780 --> 00:28:24,500 But again, as in C and in Python, take baby steps, 557 00:28:24,500 --> 00:28:27,680 and just make sure the basics of your code are working so far. 558 00:28:27,680 --> 00:28:29,750 Let me rerun Flask run. 559 00:28:29,750 --> 00:28:31,640 Let me open my URL. 560 00:28:31,640 --> 00:28:33,980 And now let me try filling out this same form again. 561 00:28:33,980 --> 00:28:36,897 And actually I'm a little annoyed that the autocomplete is popping up, 562 00:28:36,897 --> 00:28:38,250 but we can turn that off later. 563 00:28:38,250 --> 00:28:40,730 Let me go ahead and click Submit, and voila. 564 00:28:40,730 --> 00:28:43,580 Now the greet route does exist. 565 00:28:43,580 --> 00:28:46,070 Notice that slash greet is fully functional. 566 00:28:46,070 --> 00:28:49,490 It's not a not found anymore, but it's of course not doing anything useful, 567 00:28:49,490 --> 00:28:50,750 hence the "to do." 568 00:28:50,750 --> 00:28:51,650 Well that's OK. 569 00:28:51,650 --> 00:28:55,160 Let me go back here and stop the server. 570 00:28:55,160 --> 00:29:00,230 And let me instead have greet render a template called greet dot HTML. 571 00:29:00,230 --> 00:29:04,190 But recall that greet dot HTML is where I started. 572 00:29:04,190 --> 00:29:06,620 It is the file now that has this placeholder. 573 00:29:06,620 --> 00:29:12,050 So I think what I can do is just move the code that I was using earlier 574 00:29:12,050 --> 00:29:14,360 for index which no longer needs it, because index 575 00:29:14,360 --> 00:29:18,560 dot HTML has only a hardcoded static form, let me go ahead 576 00:29:18,560 --> 00:29:22,610 and just move the name parameter to my greet route instead. 577 00:29:22,610 --> 00:29:24,800 Let me go ahead and restart my server. 578 00:29:24,800 --> 00:29:27,410 Let me go ahead and open my URL. 579 00:29:27,410 --> 00:29:31,760 Let me go ahead and type my name in and hit submit, and voila. 580 00:29:31,760 --> 00:29:37,160 So now we have two fully functional routes, slash and slash greet, 581 00:29:37,160 --> 00:29:39,920 the first of which just so happens to only display 582 00:29:39,920 --> 00:29:43,670 the static form, the second of which actually happens to do something 583 00:29:43,670 --> 00:29:46,040 more interesting and greet the user. 584 00:29:46,040 --> 00:29:49,100 And I mentioned a moment ago, I was kind of annoyed by the user interface 585 00:29:49,100 --> 00:29:52,090 here, the fact that it's remembering who typed their name in before, 586 00:29:52,090 --> 00:29:54,757 I just, rubbing me the wrong way, leaks a little bit of privacy. 587 00:29:54,757 --> 00:29:57,040 So let me actually go into my index and recall 588 00:29:57,040 --> 00:30:00,640 that there's other attributes in HTML like autocomplete equals off. 589 00:30:00,640 --> 00:30:05,260 I can also do autofocus to give that textfield the blinking cursor 590 00:30:05,260 --> 00:30:08,590 by default. And now let me go ahead and restart 591 00:30:08,590 --> 00:30:11,020 my server after making this change. 592 00:30:11,020 --> 00:30:12,460 Let me go ahead and reload. 593 00:30:12,460 --> 00:30:13,330 And you know what? 594 00:30:13,330 --> 00:30:14,440 We can do a little better. 595 00:30:14,440 --> 00:30:17,980 Let's also add one of those placeholder, quote unquote name, 596 00:30:17,980 --> 00:30:20,890 just so that it's a little more clear to my visitors 597 00:30:20,890 --> 00:30:23,620 that, oh, you want me to type my name, David, here. 598 00:30:23,620 --> 00:30:24,970 Autocomplete is now off. 599 00:30:24,970 --> 00:30:26,770 I click Submit, voila. 600 00:30:26,770 --> 00:30:31,687 We now have a working, if simple, web application. 601 00:30:31,687 --> 00:30:33,520 All right, so what were the additions there? 602 00:30:33,520 --> 00:30:37,630 Same exact application as before, but we added a second route 603 00:30:37,630 --> 00:30:44,470 and a second template so that one form could submit data to the other route 604 00:30:44,470 --> 00:30:45,470 instead. 605 00:30:45,470 --> 00:30:50,050 So let me pause here to see if there's any questions or confusion before we 606 00:30:50,050 --> 00:30:53,340 continue to iterate on this. 607 00:30:53,340 --> 00:30:55,760 Questions or confusion. 608 00:30:55,760 --> 00:31:00,510 SPEAKER 1: I'm wondering how that came equals double quote name, 609 00:31:00,510 --> 00:31:05,833 is that equivalent to the name that you later specified? 610 00:31:05,833 --> 00:31:06,750 DAVID J. MALAN: It is. 611 00:31:06,750 --> 00:31:09,030 And I'll demonstrate this by changing that now. 612 00:31:09,030 --> 00:31:12,540 I called it name just because we're indeed talking about humans' names, 613 00:31:12,540 --> 00:31:14,830 but I could call this anything I want. 614 00:31:14,830 --> 00:31:19,150 So for instance in my form I'm collecting this as the person's name. 615 00:31:19,150 --> 00:31:22,390 But I could change it to first underscore name, for instance, 616 00:31:22,390 --> 00:31:24,070 if I only care about their first name. 617 00:31:24,070 --> 00:31:25,950 Let me change the placeholder to make clear 618 00:31:25,950 --> 00:31:27,660 that I only want their first name. 619 00:31:27,660 --> 00:31:30,360 Let me now go to my application dot py. 620 00:31:30,360 --> 00:31:36,510 Let me get the first underscore name HTTP parameter, and then 621 00:31:36,510 --> 00:31:42,450 in my template, greet dot HTML, let me change this to first underscore name. 622 00:31:42,450 --> 00:31:44,580 And actually I need to make one more change. 623 00:31:44,580 --> 00:31:47,540 I need to change this to first underscore name as well. 624 00:31:47,540 --> 00:31:50,790 So it's a little annoying that you have to repeat yourself all over the place, 625 00:31:50,790 --> 00:31:52,500 but they mean different things. 626 00:31:52,500 --> 00:31:55,980 In the context of application dot py, this is a parameter 627 00:31:55,980 --> 00:31:57,930 that I'm passing into my template. 628 00:31:57,930 --> 00:32:01,800 In the context of this get function, this is the HTTP parameter 629 00:32:01,800 --> 00:32:03,810 that I'm grabbing from the URL. 630 00:32:03,810 --> 00:32:07,170 And in the context of my template, this refers 631 00:32:07,170 --> 00:32:10,500 to the first of those, which is the argument I'm 632 00:32:10,500 --> 00:32:12,810 passing into render template. 633 00:32:12,810 --> 00:32:17,460 And if I reload the server, and let me go ahead and reload the form here. 634 00:32:17,460 --> 00:32:19,030 Let me type in only my first name. 635 00:32:19,030 --> 00:32:19,650 Click submit. 636 00:32:19,650 --> 00:32:23,100 A whole bunch of things changed, not in terms of output 637 00:32:23,100 --> 00:32:24,810 but in terms of functionality. 638 00:32:24,810 --> 00:32:31,180 And you'll see that now I'm using first underscore name instead of name itself. 639 00:32:31,180 --> 00:32:37,610 Other questions or confusion about routes or parameters 640 00:32:37,610 --> 00:32:40,580 in the URL, templates or otherwise? 641 00:32:40,580 --> 00:32:41,390 No? 642 00:32:41,390 --> 00:32:44,120 All right, well let me ask a question then of us. 643 00:32:44,120 --> 00:32:47,480 Let me go ahead and scroll this down just a bit to make room. 644 00:32:47,480 --> 00:32:50,090 Here, again, is my index dot HTML file. 645 00:32:50,090 --> 00:32:51,410 It contains a form. 646 00:32:51,410 --> 00:32:55,730 Here now is my greet dot HTML file, which contains just, 647 00:32:55,730 --> 00:32:58,520 hello comma so and so. 648 00:32:58,520 --> 00:33:02,038 What looks poorly designed about this? 649 00:33:02,038 --> 00:33:05,330 I'm going to go ahead and revert just to my shorter names just so a little more 650 00:33:05,330 --> 00:33:07,850 fits onto the screen at once. 651 00:33:07,850 --> 00:33:10,750 But what looks poorly designed about this? 652 00:33:10,750 --> 00:33:12,100 I claim that it's correct. 653 00:33:12,100 --> 00:33:14,810 We seem to have a working web application. 654 00:33:14,810 --> 00:33:17,480 But what is poorly designed arguably? 655 00:33:17,480 --> 00:33:19,880 BRIAN: Let's hear from Peter. 656 00:33:19,880 --> 00:33:22,550 SPEAKER 2: Well I guess you're getting it, 657 00:33:22,550 --> 00:33:27,860 so the URL is exposing the personal data of the input, whatever 658 00:33:27,860 --> 00:33:32,525 they might have put in, so I guess we'd want to use post instead to hide it. 659 00:33:32,525 --> 00:33:33,650 DAVID J. MALAN: Good catch. 660 00:33:33,650 --> 00:33:37,520 So all this time I have very deliberately but a little worrisomely 661 00:33:37,520 --> 00:33:40,487 been leaking information in the URL in the sense 662 00:33:40,487 --> 00:33:43,070 that now it's probably going to be saved by my browser, right? 663 00:33:43,070 --> 00:33:45,440 Often when you're typing something to your URL bar, 664 00:33:45,440 --> 00:33:47,360 you can see what you've searched for before, 665 00:33:47,360 --> 00:33:51,045 what websites you've been to before, and that's a good user interface 666 00:33:51,045 --> 00:33:54,170 feature in that it just helps you type your keystrokes because you can just 667 00:33:54,170 --> 00:33:56,780 hit Tab and hit Enter to finish your thought quickly. 668 00:33:56,780 --> 00:34:00,020 But it's a little invasive if you don't want people knowing where you went 669 00:34:00,020 --> 00:34:02,630 or what you searched for or if it's a lab computer 670 00:34:02,630 --> 00:34:04,190 or your siblings are using it too. 671 00:34:04,190 --> 00:34:07,730 There's a lot of reasons why you don't want your typed input ending up 672 00:34:07,730 --> 00:34:08,690 in that URL bar. 673 00:34:08,690 --> 00:34:12,380 And I proposed last week that we can avoid this by using, 674 00:34:12,380 --> 00:34:14,030 what you proposed is post. 675 00:34:14,030 --> 00:34:15,150 And indeed let's do this. 676 00:34:15,150 --> 00:34:17,389 Let me go back to my index dot HTML. 677 00:34:17,389 --> 00:34:22,340 Let me make a simple change in my HTML file, changing the method to post. 678 00:34:22,340 --> 00:34:25,370 Post is going to be almost the same as get, 679 00:34:25,370 --> 00:34:29,060 but instead of putting my parameters in the URL 680 00:34:29,060 --> 00:34:32,270 like q equals cats or name equals David in the URL, 681 00:34:32,270 --> 00:34:35,480 it's going to instead metaphorically put it lower, deeper 682 00:34:35,480 --> 00:34:37,070 inside the virtual envelope. 683 00:34:37,070 --> 00:34:39,409 So it's still being sent from the browser to server, 684 00:34:39,409 --> 00:34:43,460 but it's not going to get remembered by the browser in the URL bar. 685 00:34:43,460 --> 00:34:46,830 But if I do this I need to change my controller. 686 00:34:46,830 --> 00:34:49,820 I need my Python code to look in a somewhat different location 687 00:34:49,820 --> 00:34:50,480 to get at that. 688 00:34:50,480 --> 00:34:52,159 And it's a pretty simple change. 689 00:34:52,159 --> 00:34:53,929 Instead I have to do this. 690 00:34:53,929 --> 00:34:59,150 I have to tell Flask that the route, slash greet, 691 00:34:59,150 --> 00:35:02,420 is actually going to support a different set of methods. 692 00:35:02,420 --> 00:35:05,510 Rather than supporting get, which is the default, 693 00:35:05,510 --> 00:35:09,180 I have to pass in the somewhat cryptic argument called methods. 694 00:35:09,180 --> 00:35:12,320 And then I have to pass in literally a Python list of the methods 695 00:35:12,320 --> 00:35:13,910 I want this list to support. 696 00:35:13,910 --> 00:35:17,030 By default if you don't use this argument, all 697 00:35:17,030 --> 00:35:19,970 of these routes, the first and the second, 698 00:35:19,970 --> 00:35:23,990 have essentially this default value, methods equals, 699 00:35:23,990 --> 00:35:26,468 quote unquote get in a list, so a list of size one. 700 00:35:26,468 --> 00:35:29,510 It would be a little annoying if you had to type that all over the place, 701 00:35:29,510 --> 00:35:32,460 so the default just allows you to just type nothing at all. 702 00:35:32,460 --> 00:35:34,550 But if you want to support post, you do have 703 00:35:34,550 --> 00:35:39,020 to override this and change the get default to post explicitly. 704 00:35:39,020 --> 00:35:43,760 And you have to get the parameters from a different variable. 705 00:35:43,760 --> 00:35:48,880 Instead of using request dot args which refers to the arguments in the URL, 706 00:35:48,880 --> 00:35:51,980 you have to change it to request dot form. 707 00:35:51,980 --> 00:35:53,510 These are horribly named. 708 00:35:53,510 --> 00:35:57,770 In Flask, these global variables, request dot args and request dot form 709 00:35:57,770 --> 00:36:00,530 refer to get and post respectively. 710 00:36:00,530 --> 00:36:03,710 Better names might have been request dot get and request dot post, 711 00:36:03,710 --> 00:36:04,940 but this is what we have. 712 00:36:04,940 --> 00:36:08,000 So request dot args is for get requests in the URL. 713 00:36:08,000 --> 00:36:13,040 Request dot form is for post requests where the same info is buried deeper 714 00:36:13,040 --> 00:36:14,720 in the virtual envelope. 715 00:36:14,720 --> 00:36:17,360 So after those changes, let me go ahead and make, 716 00:36:17,360 --> 00:36:20,900 sorry not make, wrong language, Flask run. 717 00:36:20,900 --> 00:36:25,190 All right let me go ahead and open my URL, and voila. 718 00:36:25,190 --> 00:36:29,420 I'm going to type in David, click Submit, and now notice the magic. 719 00:36:29,420 --> 00:36:33,320 Now the route is still slash greet, but no one 720 00:36:33,320 --> 00:36:36,230 who uses my laptop later is going to know what my name was 721 00:36:36,230 --> 00:36:40,580 or what my Google search was or what my credit card number was 722 00:36:40,580 --> 00:36:44,870 or anything else that I might have typed into a form here like my name. 723 00:36:44,870 --> 00:36:48,090 But the output is still fully functional. 724 00:36:48,090 --> 00:36:51,108 So this indeed, to be clear, is post is what 725 00:36:51,108 --> 00:36:53,900 you would use whenever you're collecting anything remotely personal 726 00:36:53,900 --> 00:36:56,330 like people's email addresses, perhaps, or their credit 727 00:36:56,330 --> 00:36:59,780 card, or their passwords, certainly, and other values, 728 00:36:59,780 --> 00:37:04,760 but you can otherwise use get as we've been using thus far. 729 00:37:04,760 --> 00:37:06,920 Well let me ask a follow up question, because I 730 00:37:06,920 --> 00:37:08,880 think we can still do better than this. 731 00:37:08,880 --> 00:37:12,470 There's something fundamentally about the design of index dot HTML 732 00:37:12,470 --> 00:37:15,920 and greet dot HTML that feels a little suboptimal. 733 00:37:15,920 --> 00:37:21,290 And I dare say several of you noticed this same problem in this past week 734 00:37:21,290 --> 00:37:24,650 when you were just creating a few HTML files on your own. 735 00:37:24,650 --> 00:37:28,970 What was a little tedious or annoying or messy or poorly designed 736 00:37:28,970 --> 00:37:33,500 as best you could tell from creating these several HTML 737 00:37:33,500 --> 00:37:36,470 files for your own personal home page? 738 00:37:36,470 --> 00:37:40,370 BRIAN: The chat is suggesting you've repeated some HTML between the two HTML 739 00:37:40,370 --> 00:37:40,890 files. 740 00:37:40,890 --> 00:37:43,310 DAVID J. MALAN: Yeah, my god, I mean honestly by the second file, 741 00:37:43,310 --> 00:37:45,650 third file, fourth file, you're probably just copying and pasting 742 00:37:45,650 --> 00:37:48,080 your previous files and then making minor changes, 743 00:37:48,080 --> 00:37:49,250 and that's all you could do. 744 00:37:49,250 --> 00:37:51,680 With HTML and CSS alone and even JavaScript, 745 00:37:51,680 --> 00:37:54,500 you can't share HTML across multiple pages. 746 00:37:54,500 --> 00:37:57,680 Your only option this past week when serving static content 747 00:37:57,680 --> 00:38:00,560 was to copy and paste that content redundantly. 748 00:38:00,560 --> 00:38:01,340 And look at this. 749 00:38:01,340 --> 00:38:06,530 In my index dot HTML file, everything I've just highlighted from line 1 to 7 750 00:38:06,530 --> 00:38:10,580 happens to be exactly the same as everything from line 1 to 7 751 00:38:10,580 --> 00:38:12,780 in greet dot HTML. 752 00:38:12,780 --> 00:38:17,250 So here's another feature you get with Flask or any web programming framework. 753 00:38:17,250 --> 00:38:19,370 These aren't specific to Flask, per se. 754 00:38:19,370 --> 00:38:23,270 You get the ability to factor out common content. 755 00:38:23,270 --> 00:38:25,140 And so how do we go about doing this? 756 00:38:25,140 --> 00:38:26,660 Well, let me go ahead and do this. 757 00:38:26,660 --> 00:38:30,110 Let me go ahead and create a third file that by convention in Flask 758 00:38:30,110 --> 00:38:32,060 is called layout dot HTML. 759 00:38:32,060 --> 00:38:35,450 And to be safe, to be sure, I'm going to put this in my templates directory 760 00:38:35,450 --> 00:38:37,190 because again it's an HTML file. 761 00:38:37,190 --> 00:38:40,490 I'm going to go ahead and copy paste all of that same boilerplate, if you will, 762 00:38:40,490 --> 00:38:44,480 all of the commonalities, and delete what was specific to greet dot HTML. 763 00:38:44,480 --> 00:38:46,940 And I think what we're looking at, lines 1 through 10, 764 00:38:46,940 --> 00:38:52,583 is now like a template for, if you will, the layout for my other two web pages. 765 00:38:52,583 --> 00:38:54,500 So you know what, let me go ahead and do this. 766 00:38:54,500 --> 00:38:59,390 Let me use some special syntax and say block body, and then, a little weirdly, 767 00:38:59,390 --> 00:39:01,980 end block here. 768 00:39:01,980 --> 00:39:06,140 So this is Flask specific syntax or technically 769 00:39:06,140 --> 00:39:08,720 Jinja specific syntax, which is a language that Flask 770 00:39:08,720 --> 00:39:12,260 is using which someone else wrote, this is special syntax in Flask that 771 00:39:12,260 --> 00:39:15,950 essentially says put a placeholder here. 772 00:39:15,950 --> 00:39:19,920 Put a placeholder here so I can plug in other HTML in just a bit. 773 00:39:19,920 --> 00:39:21,170 So how do I use this now? 774 00:39:21,170 --> 00:39:23,460 Well let me go to my index dot HTML file, 775 00:39:23,460 --> 00:39:26,570 and let me get rid of all of the redundancy, 776 00:39:26,570 --> 00:39:29,990 boiling down index dot HTML really into its essence. 777 00:39:29,990 --> 00:39:33,090 The only thing that's special about index dot HTML was that form. 778 00:39:33,090 --> 00:39:36,590 So if I want to use the same layout that I just created, let me go ahead 779 00:39:36,590 --> 00:39:41,750 and say up here using that special syntax, extends layout dot HTML, 780 00:39:41,750 --> 00:39:46,700 and then down here let me say, here is my body block, if you will. 781 00:39:46,700 --> 00:39:47,960 Let me un-indent that a bit. 782 00:39:47,960 --> 00:39:51,810 And then let me say down here end block. 783 00:39:51,810 --> 00:39:55,850 So again, syntax is weird, but the ideas are pretty similar. 784 00:39:55,850 --> 00:39:58,430 This is almost similar in spirit to our header files 785 00:39:58,430 --> 00:40:00,800 in C, where you could factor out some commonalities 786 00:40:00,800 --> 00:40:02,570 and just reuse them in multiple places. 787 00:40:02,570 --> 00:40:04,653 Here it's a little fancier because you can kind of 788 00:40:04,653 --> 00:40:07,010 have this blueprint, this layout, literally 789 00:40:07,010 --> 00:40:09,140 that you can then plug different content into. 790 00:40:09,140 --> 00:40:13,970 So this first line says, hey Flask, the following file, index dot HTML, 791 00:40:13,970 --> 00:40:17,020 essentially inherits from, it extends my default layout. 792 00:40:17,020 --> 00:40:18,020 Well what's that layout? 793 00:40:18,020 --> 00:40:18,800 It's this. 794 00:40:18,800 --> 00:40:23,300 Notice that this layout defines this placeholder, arbitrarily called body. 795 00:40:23,300 --> 00:40:26,420 I could have called it x or y or z, but I'm going to call it body. 796 00:40:26,420 --> 00:40:26,990 Why? 797 00:40:26,990 --> 00:40:30,770 Because really it's like 100% of the contents of my body. 798 00:40:30,770 --> 00:40:32,420 So seems like a good name. 799 00:40:32,420 --> 00:40:35,750 And then in index dot HTML, I just now need to tell Flask, 800 00:40:35,750 --> 00:40:40,340 here comes some code that you should plug into that placeholder. 801 00:40:40,340 --> 00:40:45,090 And you can plug one or more lines of HTML code in here. 802 00:40:45,090 --> 00:40:46,670 So let me go ahead and save this. 803 00:40:46,670 --> 00:40:51,230 Let me go ahead now and go to greet, similarly delete all that redundancy, 804 00:40:51,230 --> 00:40:56,060 and now let me go up here and say again, extends layout dot HTML, 805 00:40:56,060 --> 00:40:59,930 and then down here let me say here is my body block. 806 00:40:59,930 --> 00:41:03,560 Let me just un-indent this slightly, and then let me say end block 807 00:41:03,560 --> 00:41:05,310 and save that file. 808 00:41:05,310 --> 00:41:08,150 So now these HTML files are quickly looking weird. 809 00:41:08,150 --> 00:41:10,190 Like there's barely any HTML in here, it's 810 00:41:10,190 --> 00:41:15,950 really just text and weird Flask syntax, same thing in index dot HTML, 811 00:41:15,950 --> 00:41:19,010 but again, this is one of the values of a web application. 812 00:41:19,010 --> 00:41:21,228 Where you have a programming language like Python, 813 00:41:21,228 --> 00:41:23,270 you can factor out those commonalities and really 814 00:41:23,270 --> 00:41:26,560 start generating pages dynamically just like the Googles and Facebooks 815 00:41:26,560 --> 00:41:29,030 and others of the world do every day. 816 00:41:29,030 --> 00:41:32,950 So let me go ahead now and rerun Flask run 817 00:41:32,950 --> 00:41:36,310 and cross my fingers as always because I made a whole bunch of changes here. 818 00:41:36,310 --> 00:41:40,870 Let me open my URL, and voila, seems to be working OK so far. 819 00:41:40,870 --> 00:41:44,630 Let me go ahead and, before I submit this, let me show you the page source. 820 00:41:44,630 --> 00:41:48,040 Notice that it's there it's not quite as pretty printed, 821 00:41:48,040 --> 00:41:50,590 like the indentation's a little off, but that's OK. 822 00:41:50,590 --> 00:41:52,720 Your templates should be well styled. 823 00:41:52,720 --> 00:41:55,550 Everything should be beautifully indented in your templates. 824 00:41:55,550 --> 00:41:58,120 But if your templates are then rendered by Flask 825 00:41:58,120 --> 00:41:59,860 and the whitespace isn't quite as pretty, 826 00:41:59,860 --> 00:42:02,570 that doesn't matter because again, the browser doesn't care. 827 00:42:02,570 --> 00:42:05,020 But indeed, I have a full-fledged complete web page. 828 00:42:05,020 --> 00:42:06,610 Let me submit this form. 829 00:42:06,610 --> 00:42:07,940 It seems to still work. 830 00:42:07,940 --> 00:42:09,700 That's my slash greet route. 831 00:42:09,700 --> 00:42:12,100 I'm seeing Hello, David, and if I view page source here, 832 00:42:12,100 --> 00:42:15,183 notice another confirm form submission. 833 00:42:15,183 --> 00:42:16,600 This is actually a safety feature. 834 00:42:16,600 --> 00:42:19,270 You don't want websites tricking you into like checking out 835 00:42:19,270 --> 00:42:21,610 twice with your credit card via post, so I'm 836 00:42:21,610 --> 00:42:23,500 going to go ahead and click reload manually 837 00:42:23,500 --> 00:42:26,200 which confirms that I want to resubmit this form because there's 838 00:42:26,200 --> 00:42:27,700 nothing dangerous about it. 839 00:42:27,700 --> 00:42:30,310 There is now my greet route. 840 00:42:30,310 --> 00:42:33,790 So this probably would have saved you all a lot of headache or tedium 841 00:42:33,790 --> 00:42:37,090 or copy paste, you just didn't have this tool in the tool kit last week. 842 00:42:37,090 --> 00:42:43,190 You cannot do it with HTML and CSS or even JavaScript alone in the browser. 843 00:42:43,190 --> 00:42:47,080 So this is where you have templates really shining. 844 00:42:47,080 --> 00:42:49,630 Not only can you have templates use two curly braces 845 00:42:49,630 --> 00:42:54,760 to plug in values of variables, you can use this curly brace percent sign 846 00:42:54,760 --> 00:43:00,420 syntax and plug in actual contents of other files. 847 00:43:00,420 --> 00:43:01,140 Whew. 848 00:43:01,140 --> 00:43:04,120 Questions or confusion? 849 00:43:04,120 --> 00:43:05,870 BRIAN: There was a clarification question. 850 00:43:05,870 --> 00:43:07,820 Could you tell us what is [? Jinja? ?] 851 00:43:07,820 --> 00:43:09,320 DAVID J. MALAN: Yes, so I skirted over that because I 852 00:43:09,320 --> 00:43:11,360 was getting annoyed at just like how many new terms there 853 00:43:11,360 --> 00:43:13,490 are today and frankly in the web programming world 854 00:43:13,490 --> 00:43:14,740 that we're sort of stuck with. 855 00:43:14,740 --> 00:43:17,813 So this is a good example of code reuse. 856 00:43:17,813 --> 00:43:19,730 There's a lot of smart people out there, a lot 857 00:43:19,730 --> 00:43:21,080 of people solving different problems. 858 00:43:21,080 --> 00:43:23,600 It would be a little annoying and a little arrogant if all of us 859 00:43:23,600 --> 00:43:25,808 tried to solve all of the world's computing problems. 860 00:43:25,808 --> 00:43:31,580 And so the authors of Flask decided that for their template feature 861 00:43:31,580 --> 00:43:34,830 they would not reinvent the wheel and come up with their own syntax. 862 00:43:34,830 --> 00:43:38,840 They would use someone else's existing crazy syntax, if you will, 863 00:43:38,840 --> 00:43:41,480 that uses the double curly braces and the curly brace 864 00:43:41,480 --> 00:43:43,790 and the percent signs so that they're just combining 865 00:43:43,790 --> 00:43:45,750 one person's language with another. 866 00:43:45,750 --> 00:43:46,710 And this is so common. 867 00:43:46,710 --> 00:43:48,710 And this is a good thing because technically you 868 00:43:48,710 --> 00:43:52,670 can plug in a different language if you really are anti-Jinja for some reason, 869 00:43:52,670 --> 00:43:55,530 you just hate the syntax, you can actually use something else. 870 00:43:55,530 --> 00:43:57,800 And so this is actually a demonstration in computing 871 00:43:57,800 --> 00:44:01,700 of really a component based design where you 872 00:44:01,700 --> 00:44:04,820 can plug different pieces of software together and have 873 00:44:04,820 --> 00:44:06,110 them still interoperate. 874 00:44:06,110 --> 00:44:09,680 And we'll add to the course's website links to Jinja's documentation, 875 00:44:09,680 --> 00:44:13,590 and we'll see in a little bit what more you can do with Jinja in the template. 876 00:44:13,590 --> 00:44:17,060 So again, Jinja just refers to really the double curly brace syntax 877 00:44:17,060 --> 00:44:24,440 and the curly brace percent sign syntax that appears in our templates files. 878 00:44:24,440 --> 00:44:27,770 All right, one last feature when it comes to saying hello. 879 00:44:27,770 --> 00:44:30,320 Thus far in application dot py, I've been 880 00:44:30,320 --> 00:44:34,430 keeping things a little conceptually simple if complicated syntactically 881 00:44:34,430 --> 00:44:38,330 by having two separate routes, one route, slash, for my form, 882 00:44:38,330 --> 00:44:44,660 and then another route for my actual greet route that 883 00:44:44,660 --> 00:44:46,430 actually displays the information. 884 00:44:46,430 --> 00:44:49,190 But strictly speaking I can be a little clever 885 00:44:49,190 --> 00:44:51,770 and combine these routes, if only because if you're 886 00:44:51,770 --> 00:44:54,650 building a pretty sophisticated website that's got lots of routes, 887 00:44:54,650 --> 00:44:58,550 it's kind of annoying if like every route needs two routes if one form has 888 00:44:58,550 --> 00:44:59,880 to submit to another. 889 00:44:59,880 --> 00:45:03,230 So let me just propose that we tighten up our implementation 890 00:45:03,230 --> 00:45:05,780 and actually reuse our one route. 891 00:45:05,780 --> 00:45:07,850 So let me go ahead and delete my greet route, 892 00:45:07,850 --> 00:45:11,640 just because it's bothering me that I'm getting a little redundancy there, 893 00:45:11,640 --> 00:45:15,140 and let me go ahead and say that my default route, my index, 894 00:45:15,140 --> 00:45:19,310 will actually support both methods, get and post. 895 00:45:19,310 --> 00:45:23,240 So I'm going to use the same route, not only to show the user the form, 896 00:45:23,240 --> 00:45:26,250 but also to say hello to the user as well. 897 00:45:26,250 --> 00:45:30,260 So I need to be able to support both get and post on the same route. 898 00:45:30,260 --> 00:45:31,560 So how am I going to do this? 899 00:45:31,560 --> 00:45:33,410 Well, let me go ahead and do this. 900 00:45:33,410 --> 00:45:40,690 What I can do is if request dot method equals equals get, 901 00:45:40,690 --> 00:45:45,460 then I can actually go ahead and execute this line of code here. 902 00:45:45,460 --> 00:45:50,950 Else if request dot method equals equals post, then what I'm going to do 903 00:45:50,950 --> 00:45:55,990 is this, return, render template, greet dot HTML, 904 00:45:55,990 --> 00:45:59,515 and I'm going to pass in a name of request dot form 905 00:45:59,515 --> 00:46:03,890 dot get, name, and then a default value of world. 906 00:46:03,890 --> 00:46:04,690 So nothing new. 907 00:46:04,690 --> 00:46:07,000 That's just the code that I deleted a moment ago. 908 00:46:07,000 --> 00:46:09,760 But notice now I'm reusing the same route, 909 00:46:09,760 --> 00:46:13,370 and I'm just checking logically in my controller code, 910 00:46:13,370 --> 00:46:16,162 if you will, well if the method came in as get, 911 00:46:16,162 --> 00:46:17,620 go ahead and just display the form. 912 00:46:17,620 --> 00:46:21,640 If the method came in as post, go ahead and greet the user. 913 00:46:21,640 --> 00:46:23,110 Now why is this going to work? 914 00:46:23,110 --> 00:46:26,140 Well it turns out, whenever you visit a URL on the internet, 915 00:46:26,140 --> 00:46:31,090 like HTTP colon slash slash, www.harvard.edu or yale.edu 916 00:46:31,090 --> 00:46:36,280 or google.com, you have always been making get requests. 917 00:46:36,280 --> 00:46:39,520 In fact, recall last week when we looked at those sample HTTP requests, 918 00:46:39,520 --> 00:46:41,920 and the headers, everything we did last week 919 00:46:41,920 --> 00:46:44,800 had the keyword get by default in the envelope. 920 00:46:44,800 --> 00:46:48,370 So get does not have anything fundamentally to do with forms, 921 00:46:48,370 --> 00:46:51,070 it's actually the default HTTP verb that's 922 00:46:51,070 --> 00:46:53,680 used whenever you just visit any URL. 923 00:46:53,680 --> 00:46:57,040 Any time you visit a URL on the web you are using get by default. 924 00:46:57,040 --> 00:47:01,780 When you submit a form, you are potentially using get as I did first, 925 00:47:01,780 --> 00:47:05,530 or you are using post as I did second. 926 00:47:05,530 --> 00:47:08,560 So what's the takeaway here? 927 00:47:08,560 --> 00:47:12,100 Well let me go ahead and make one change to my form. 928 00:47:12,100 --> 00:47:15,300 I do want to submit via post. 929 00:47:15,300 --> 00:47:17,425 I'm going to submit though no longer to slash greet 930 00:47:17,425 --> 00:47:19,610 but just to my default route. 931 00:47:19,610 --> 00:47:23,730 And if I did everything right here, let me go ahead and run Flask run, 932 00:47:23,730 --> 00:47:30,850 let me open up my URL as before, and I'm at my slash route. 933 00:47:30,850 --> 00:47:35,440 Notice if I view my page source, the action is going to be slash also, 934 00:47:35,440 --> 00:47:39,430 so I'm sort of using the same route for two different pieces of functionality. 935 00:47:39,430 --> 00:47:43,720 Let me type in my name, click Submit, and voila, amazingly, it worked. 936 00:47:43,720 --> 00:47:46,540 Hello, David, but my route has not changed. 937 00:47:46,540 --> 00:47:48,680 Now, why is this why is this useful? 938 00:47:48,680 --> 00:47:49,588 It may or may not be. 939 00:47:49,588 --> 00:47:52,630 It's just the capability you now have because if you can express yourself 940 00:47:52,630 --> 00:47:56,410 programmatically in Python, you can distinguish between the two verbs 941 00:47:56,410 --> 00:48:00,580 get and post that are inside of your incoming HTTP request, and if anything 942 00:48:00,580 --> 00:48:04,570 this just means you don't need twice as many routes just to have one thing pass 943 00:48:04,570 --> 00:48:06,550 to another, and it turns out there's also 944 00:48:06,550 --> 00:48:11,350 other features that derive from just being able to reuse the same routes. 945 00:48:11,350 --> 00:48:13,630 But more on that down the road. 946 00:48:13,630 --> 00:48:19,310 All right, any questions then on saying hello, Flask, or these routes? 947 00:48:19,310 --> 00:48:19,810 No? 948 00:48:19,810 --> 00:48:20,360 All right. 949 00:48:20,360 --> 00:48:23,590 Well just as a teaser here, here is a screenshot 950 00:48:23,590 --> 00:48:26,860 of pretty much the very first web application I made back in the day. 951 00:48:26,860 --> 00:48:29,860 When I was an undergraduate, I got involved in intramural sports, 952 00:48:29,860 --> 00:48:32,920 not in an athletic sense but in a computer science sense. 953 00:48:32,920 --> 00:48:36,790 I volunteered to actually build the very first website for Harvard's freshman 954 00:48:36,790 --> 00:48:39,700 intramural sports program, otherwise known as Frosh IMs. 955 00:48:39,700 --> 00:48:43,750 At the time we were using paper to write your names down on and email 956 00:48:43,750 --> 00:48:45,910 addresses down on, your choices of sports, 957 00:48:45,910 --> 00:48:49,150 we would walk across Harvard Yard, the grassy area in the middle of Harvard, 958 00:48:49,150 --> 00:48:52,210 slide it under the door of one of the proctors or resident advisors, 959 00:48:52,210 --> 00:48:53,980 and voila, we were registered for sports. 960 00:48:53,980 --> 00:48:55,695 But there was no website. 961 00:48:55,695 --> 00:48:57,820 There was an internet but there was no website yet. 962 00:48:57,820 --> 00:48:59,140 So this was late 90s. 963 00:48:59,140 --> 00:49:01,510 So I thought it would be fun to implement 964 00:49:01,510 --> 00:49:03,850 that same idea of a piece of paper for registering 965 00:49:03,850 --> 00:49:05,750 for sports in a web browser. 966 00:49:05,750 --> 00:49:10,690 And now unfortunately I only knew C and maybe some C++ at the time and a couple 967 00:49:10,690 --> 00:49:12,400 of other languages from other CS courses. 968 00:49:12,400 --> 00:49:14,050 I knew nothing about web programming. 969 00:49:14,050 --> 00:49:16,840 So I taught myself how to web program with the help of lots 970 00:49:16,840 --> 00:49:18,490 of questions and answers from friends. 971 00:49:18,490 --> 00:49:22,150 I happened to use a language called Perl, and the result at the end 972 00:49:22,150 --> 00:49:26,200 was this frightening design here with lots of menu options 973 00:49:26,200 --> 00:49:28,930 up top that use JavaScript and some images here 974 00:49:28,930 --> 00:49:32,170 and some CSV files essentially on the backend that 975 00:49:32,170 --> 00:49:33,850 stored all of the registration data. 976 00:49:33,850 --> 00:49:36,230 I knew nothing about databases at the time. 977 00:49:36,230 --> 00:49:38,738 But it was my first foray into web programming. 978 00:49:38,738 --> 00:49:40,780 And what we thought we'd do after our first break 979 00:49:40,780 --> 00:49:47,170 here is reimplement the idea of a registration system using HTML, CSS, 980 00:49:47,170 --> 00:49:51,883 and Python and ultimately SQL to reimplement the same idea, 981 00:49:51,883 --> 00:49:53,800 worrying even less today about the aesthetics. 982 00:49:53,800 --> 00:49:56,342 But let's go ahead and take our first five minute break here. 983 00:49:56,342 --> 00:49:57,860 And when we come back Frosh IMs. 984 00:49:57,860 --> 00:49:59,380 All right, we are back. 985 00:49:59,380 --> 00:50:02,200 So the goal at hand is to implement the most primitive of features 986 00:50:02,200 --> 00:50:04,690 that I first implemented via this Frosh IMs 987 00:50:04,690 --> 00:50:08,110 website years ago, that of allowing students to register for sports. 988 00:50:08,110 --> 00:50:11,290 And to register for a sport, let's collect everyone's name and maybe 989 00:50:11,290 --> 00:50:13,428 the sport for which they want to register. 990 00:50:13,428 --> 00:50:14,720 So how are we going to do this? 991 00:50:14,720 --> 00:50:19,120 Well, let me go ahead and copy just the layout from our previous hello examples 992 00:50:19,120 --> 00:50:20,920 just because it's pretty good boilerplate. 993 00:50:20,920 --> 00:50:22,670 And I'm actually going to make one change. 994 00:50:22,670 --> 00:50:27,340 It turns out that it's very easy to make your website pretty mobile friendly 995 00:50:27,340 --> 00:50:29,290 just by adding a couple of lines of code. 996 00:50:29,290 --> 00:50:32,890 In particular in my head here I'm going to go ahead and add a tag called meta. 997 00:50:32,890 --> 00:50:34,690 It's going to have a name of viewport. 998 00:50:34,690 --> 00:50:36,910 Viewport refers to the rectangular region 999 00:50:36,910 --> 00:50:40,060 that defines most of your web browsers' user interface. 1000 00:50:40,060 --> 00:50:43,840 The content of this meta tag is going to be initial scale 1001 00:50:43,840 --> 00:50:47,830 equals 1 and width equals device width. 1002 00:50:47,830 --> 00:50:50,380 And this last keyword is kind of the magic. 1003 00:50:50,380 --> 00:50:53,200 This incantation here essentially tells the browser 1004 00:50:53,200 --> 00:50:57,325 whatever the user's, whatever the width of the user's device 1005 00:50:57,325 --> 00:51:00,490 is, assume that that's the maximum width for my web page, 1006 00:51:00,490 --> 00:51:02,920 and it's going to scale my font sizes automatically 1007 00:51:02,920 --> 00:51:06,790 up or down based on whether you're using a laptop or desktop or iPhone 1008 00:51:06,790 --> 00:51:09,105 or Android phone or something else altogether. 1009 00:51:09,105 --> 00:51:11,980 There's other things you need to do to make your websites responsive, 1010 00:51:11,980 --> 00:51:15,200 so to speak, and it's helpful to use libraries like Bootstrap for that, 1011 00:51:15,200 --> 00:51:18,310 But this minimally helps at least address issues of font size. 1012 00:51:18,310 --> 00:51:20,720 So I'll start including that here as well. 1013 00:51:20,720 --> 00:51:24,880 Now let me go into my application dot py, which unfortunately for Frosh IMs 1014 00:51:24,880 --> 00:51:25,540 is empty. 1015 00:51:25,540 --> 00:51:29,770 And indeed to be clear, over the break I created, application dot py is empty, 1016 00:51:29,770 --> 00:51:32,410 a templates directory, and inside my templates directory 1017 00:51:32,410 --> 00:51:34,090 is just that layout dot HTML. 1018 00:51:34,090 --> 00:51:36,380 So we've got a little bit of work to do here together. 1019 00:51:36,380 --> 00:51:39,370 So let's go ahead and start building out this application. 1020 00:51:39,370 --> 00:51:44,770 Let me go ahead and import from Flask the Flask function itself 1021 00:51:44,770 --> 00:51:47,030 plus render template which I bet we're going to need, 1022 00:51:47,030 --> 00:51:49,738 and then also request which we're probably going to need as well. 1023 00:51:49,738 --> 00:51:54,070 Let me initialize the application with this Flask function using 1024 00:51:54,070 --> 00:51:55,370 underscore underscore name. 1025 00:51:55,370 --> 00:51:57,470 So again, that's literally how we began earlier. 1026 00:51:57,470 --> 00:51:59,928 And let's just go ahead and start defining our first route. 1027 00:51:59,928 --> 00:52:02,117 App dot route, quote unquote slash. 1028 00:52:02,117 --> 00:52:05,200 Let me define a function called index, but again I could call it anything, 1029 00:52:05,200 --> 00:52:06,992 but that's good convention, and just to get 1030 00:52:06,992 --> 00:52:12,880 me started I could really do this quickly and say return "to do," 1031 00:52:12,880 --> 00:52:15,220 but I'm kind of confident now in my ability 1032 00:52:15,220 --> 00:52:18,620 to at least use render template. 1033 00:52:18,620 --> 00:52:21,310 So let's at least render a template called index dot HTML 1034 00:52:21,310 --> 00:52:23,930 that admittedly does not yet exist. 1035 00:52:23,930 --> 00:52:25,060 So let's make it exist. 1036 00:52:25,060 --> 00:52:29,837 Let me go ahead and create a new file called index dot HTML. 1037 00:52:29,837 --> 00:52:31,670 And again I could call this whatever I want, 1038 00:52:31,670 --> 00:52:33,560 but if this is going to be my default route, 1039 00:52:33,560 --> 00:52:36,320 I might as well call my default page the most common default 1040 00:52:36,320 --> 00:52:38,360 name, which is index dot HTML. 1041 00:52:38,360 --> 00:52:41,750 Let me store it in my Frosh IMs folder and my templates folder 1042 00:52:41,750 --> 00:52:43,880 so that it's in the proper place. 1043 00:52:43,880 --> 00:52:49,730 In here, let me go ahead and say that this extends my layout dot HTML. 1044 00:52:49,730 --> 00:52:54,020 And then down here let me say my body block will be whatever's in here, 1045 00:52:54,020 --> 00:52:56,780 and then my end block will close that. 1046 00:52:56,780 --> 00:52:58,800 In here, now I'm feeling a little uncomfortable 1047 00:52:58,800 --> 00:53:01,550 with how much code I've written so let's just put a "to do" there, 1048 00:53:01,550 --> 00:53:03,342 and let's make sure this whole thing works. 1049 00:53:03,342 --> 00:53:08,400 So let me go back into my directory, do Flask run, enter. 1050 00:53:08,400 --> 00:53:12,170 All right, go ahead and open up this browser tab, and it just says, "to do." 1051 00:53:12,170 --> 00:53:13,920 So I think I'm in a good place, and indeed 1052 00:53:13,920 --> 00:53:16,570 if I view page source I see a full fledged web page, 1053 00:53:16,570 --> 00:53:19,718 including that meta tag we just added, but with just a big to do here. 1054 00:53:19,718 --> 00:53:20,760 Now what do I want to do? 1055 00:53:20,760 --> 00:53:22,510 The biggest thing I want to do is actually 1056 00:53:22,510 --> 00:53:24,900 have students be able to register for a sport. 1057 00:53:24,900 --> 00:53:28,810 So let's go ahead and define ourselves an HTML form via which to do this. 1058 00:53:28,810 --> 00:53:33,820 So inside of my body block in my index dot HTML template. 1059 00:53:33,820 --> 00:53:37,770 Let's go ahead and first just call this the registration page with an H1 tag, 1060 00:53:37,770 --> 00:53:39,840 and then let me go ahead and give myself a form. 1061 00:53:39,840 --> 00:53:43,530 The action will be, I mean, the sky's the limit, let's keep it simple 1062 00:53:43,530 --> 00:53:46,200 and just do slash register rather than complicate things 1063 00:53:46,200 --> 00:53:48,280 by using the same route again. 1064 00:53:48,280 --> 00:53:52,260 Let's keep things a little private, so let's do a method of post 1065 00:53:52,260 --> 00:53:55,290 so that my roommates don't know what sports I'm registering for or not 1066 00:53:55,290 --> 00:53:56,333 registering for. 1067 00:53:56,333 --> 00:53:59,000 And then in here let's go ahead and ask the user for their name. 1068 00:53:59,000 --> 00:54:02,730 So let's go ahead and do an input, name equals name, 1069 00:54:02,730 --> 00:54:07,830 where the name of this input is going to be name in the human sense. 1070 00:54:07,830 --> 00:54:12,400 The type of that box will be text, and let's add some of the fanciness 1071 00:54:12,400 --> 00:54:12,930 as before. 1072 00:54:12,930 --> 00:54:16,470 Autocomplete equals off, or oof. 1073 00:54:16,470 --> 00:54:22,470 Autofocus, whoops, autofocus, and then over here a placeholder 1074 00:54:22,470 --> 00:54:25,100 so that it's self-describing of name. 1075 00:54:25,100 --> 00:54:25,600 All right. 1076 00:54:25,600 --> 00:54:28,980 And then let me go ahead and give myself a submit button, 1077 00:54:28,980 --> 00:54:34,290 input type equals submit, and let's add a value of register, 1078 00:54:34,290 --> 00:54:37,200 just to make the website a little more user friendly. 1079 00:54:37,200 --> 00:54:39,310 Let me go ahead and stop my server and restart it 1080 00:54:39,310 --> 00:54:41,730 so I can reload all of these changes, and let 1081 00:54:41,730 --> 00:54:45,840 me go over to this URL again, and voila, we have the beginnings of a form. 1082 00:54:45,840 --> 00:54:48,520 It's only asking for name, so it's not quite there. 1083 00:54:48,520 --> 00:54:50,440 So I need to ask for some sports as well. 1084 00:54:50,440 --> 00:54:51,940 Now there's a bunch of ways we can do this, 1085 00:54:51,940 --> 00:54:54,482 and even though you might not have seen them all yet in CS50, 1086 00:54:54,482 --> 00:54:57,990 you've certainly used them on the actual internet when you visiting websites. 1087 00:54:57,990 --> 00:54:59,700 So let's do a drop down menu initially. 1088 00:54:59,700 --> 00:55:03,330 Let me do what's called the select menu because you select an option, the name 1089 00:55:03,330 --> 00:55:05,160 of which is going to be "sport." 1090 00:55:05,160 --> 00:55:07,277 Select menus if you read the documentation 1091 00:55:07,277 --> 00:55:09,360 or follow an online tutorial, you'll see that they 1092 00:55:09,360 --> 00:55:11,580 must have children called options. 1093 00:55:11,580 --> 00:55:15,070 And children must have values. 1094 00:55:15,070 --> 00:55:17,610 So for instance, let's use a value of how 1095 00:55:17,610 --> 00:55:20,940 about "dodgeball," which is a common intramural sport. 1096 00:55:20,940 --> 00:55:24,150 And then inside of the option tag, you actually 1097 00:55:24,150 --> 00:55:27,610 have to say, much like a link, what the human should see. 1098 00:55:27,610 --> 00:55:30,495 So I'm just going to redundantly say dodgeball here too. 1099 00:55:30,495 --> 00:55:33,120 And let me go ahead and make that my life a little easier here. 1100 00:55:33,120 --> 00:55:37,500 Let me, "to do," "to do," just to speed things up. 1101 00:55:37,500 --> 00:55:39,850 Let me do a little bit of copy paste here. 1102 00:55:39,850 --> 00:55:46,920 And how about we change this one to flag football, flag football. 1103 00:55:46,920 --> 00:55:50,412 Over here let's do, say, soccer and soccer. 1104 00:55:50,412 --> 00:55:53,370 And again just like links there might be this duality, the same values, 1105 00:55:53,370 --> 00:55:55,223 but they don't have to be the same. 1106 00:55:55,223 --> 00:55:56,640 But for now, we'll keep it simple. 1107 00:55:56,640 --> 00:55:58,170 This is what the computer will see. 1108 00:55:58,170 --> 00:56:00,450 This is what the human will see. 1109 00:56:00,450 --> 00:56:04,650 And then down here we'll call this ultimate Frisbee and here 1110 00:56:04,650 --> 00:56:07,980 the same thing, ultimate Frisbee. 1111 00:56:07,980 --> 00:56:10,990 OK, so now I have a working drop down menu. 1112 00:56:10,990 --> 00:56:15,300 So let me go ahead and prove as much by restarting my server, 1113 00:56:15,300 --> 00:56:18,000 visiting my same URL, and voila. 1114 00:56:18,000 --> 00:56:21,780 The user interface is kind of ugly, definitely very minimalist, 1115 00:56:21,780 --> 00:56:25,275 but if I now type in my name David, notice that by default dodgeball 1116 00:56:25,275 --> 00:56:28,965 is selected because one of those options should be, but I can actually fix that. 1117 00:56:28,965 --> 00:56:30,840 Let me, I don't like how I'm forcing everyone 1118 00:56:30,840 --> 00:56:32,298 to think they have to do dodgeball. 1119 00:56:32,298 --> 00:56:35,770 Let me do an option here with an empty value for instance. 1120 00:56:35,770 --> 00:56:38,160 And I can even say something up here, for instance, 1121 00:56:38,160 --> 00:56:42,650 like let's just say what it is, sports, so, with no value. 1122 00:56:42,650 --> 00:56:45,030 So it's not an actual valid option. 1123 00:56:45,030 --> 00:56:46,920 Let me go ahead and open my URL now. 1124 00:56:46,920 --> 00:56:49,360 OK, so now I see sport in the dropdown too. 1125 00:56:49,360 --> 00:56:54,570 So David, sport, OK, it's a little weird that you can register for sports. 1126 00:56:54,570 --> 00:56:55,770 That's not really a thing. 1127 00:56:55,770 --> 00:56:57,370 So let me fix that. 1128 00:56:57,370 --> 00:57:00,240 And it turns out if you read the documentation for a select menu, 1129 00:57:00,240 --> 00:57:07,780 you can actually disable the option and also, let's say, select it by default. 1130 00:57:07,780 --> 00:57:09,780 So these are just additional attributes that you 1131 00:57:09,780 --> 00:57:12,840 would discover in the documentation for the option tag that 1132 00:57:12,840 --> 00:57:16,500 now let me make the user interface a little more robust just so that users 1133 00:57:16,500 --> 00:57:18,510 aren't registering for "sport." 1134 00:57:18,510 --> 00:57:22,320 Let me go ahead and do David, and now notice, sport is selected by default, 1135 00:57:22,320 --> 00:57:23,160 but it's grayed out. 1136 00:57:23,160 --> 00:57:24,930 It's not a valid value anymore. 1137 00:57:24,930 --> 00:57:26,940 So minor user interface improvement. 1138 00:57:26,940 --> 00:57:28,373 Dodgeball sounds amazing. 1139 00:57:28,373 --> 00:57:31,540 That was not an intramural sport in my day, but it apparently is these days. 1140 00:57:31,540 --> 00:57:33,360 So let me go ahead and register for this. 1141 00:57:33,360 --> 00:57:35,160 OK, but, of course, not found. 1142 00:57:35,160 --> 00:57:36,240 Well why is that? 1143 00:57:36,240 --> 00:57:38,250 Well if we look at the URL I just ended up at, 1144 00:57:38,250 --> 00:57:41,070 I've not implemented my slash register route yet. 1145 00:57:41,070 --> 00:57:42,270 All right, so let's do that. 1146 00:57:42,270 --> 00:57:46,350 To do that, I need to go back into application dot py, and let's go ahead 1147 00:57:46,350 --> 00:57:47,790 and do some registration trickery. 1148 00:57:47,790 --> 00:57:51,240 App dot routes slash register, I'm going to define 1149 00:57:51,240 --> 00:57:53,250 a function that I might as well call register, 1150 00:57:53,250 --> 00:57:55,380 but I could, again, call it anything I want. 1151 00:57:55,380 --> 00:57:57,660 And in this function let's keep it simple initially. 1152 00:57:57,660 --> 00:58:01,890 Let's just go ahead and return a template called success 1153 00:58:01,890 --> 00:58:04,830 and just presume that the registration was successful. 1154 00:58:04,830 --> 00:58:10,190 And in fact, let me go ahead and create a new file called 1155 00:58:10,190 --> 00:58:15,140 success dot HTML in the Frosh IMs templates directory, 1156 00:58:15,140 --> 00:58:19,640 and let me make sure that also extends layout dot HTML, 1157 00:58:19,640 --> 00:58:24,590 and that it has a block body, and, for good measure, end block. 1158 00:58:24,590 --> 00:58:27,410 And then down here, I'm going to keep this so simple for now. 1159 00:58:27,410 --> 00:58:29,788 You are registered, exclamation point. 1160 00:58:29,788 --> 00:58:31,580 Not really registering anyone for anything, 1161 00:58:31,580 --> 00:58:33,390 but I'm going to claim that they were. 1162 00:58:33,390 --> 00:58:39,850 So now if I rerun my application, and I go back to my form here, 1163 00:58:39,850 --> 00:58:46,030 and I now re-register David for dodgeball and click Register, huh. 1164 00:58:46,030 --> 00:58:47,650 Now it's a bug. 1165 00:58:47,650 --> 00:58:51,520 And let me pause here just to see if the pieces are fitting together. 1166 00:58:51,520 --> 00:58:55,960 Method not allowed, even though I'm at slash register. 1167 00:58:55,960 --> 00:58:57,730 Any thoughts on how to fix this? 1168 00:58:57,730 --> 00:58:59,590 Method not allowed? 1169 00:58:59,590 --> 00:59:01,930 And notice, you can even see in my terminal window 1170 00:59:01,930 --> 00:59:09,080 in red an error message, status code 405 which means method not allowed, 1171 00:59:09,080 --> 00:59:12,130 which is a rare one but I indeed screwed up. 1172 00:59:12,130 --> 00:59:14,890 Yeah, over to Santiago? 1173 00:59:14,890 --> 00:59:16,840 SANTIAGO: Yeah, I think that when you defined 1174 00:59:16,840 --> 00:59:21,210 the app dot route for read, or register, [INAUDIBLE] 1175 00:59:21,210 --> 00:59:24,252 you didn't specify a methods is post. 1176 00:59:24,252 --> 00:59:26,710 DAVID J. MALAN: Yeah, so by default my methods are all get, 1177 00:59:26,710 --> 00:59:28,870 but if I want to use post for privacy's sake, 1178 00:59:28,870 --> 00:59:32,110 recall that I just have to tell Flask that the methods I want you to support 1179 00:59:32,110 --> 00:59:36,100 for this route are this list of verbs or methods, 1180 00:59:36,100 --> 00:59:39,207 and that list is going to be of size one with just the keyword post in it. 1181 00:59:39,207 --> 00:59:42,040 So again, when you encounter these issues, which you absolutely will 1182 00:59:42,040 --> 00:59:43,690 when doing all of this for the first time, 1183 00:59:43,690 --> 00:59:46,720 don't worry so much about the specifics of the error message, but the ideas. 1184 00:59:46,720 --> 00:59:47,500 Like what's gone wrong? 1185 00:59:47,500 --> 00:59:48,000 Method. 1186 00:59:48,000 --> 00:59:48,970 Method not allowed. 1187 00:59:48,970 --> 00:59:49,870 What could that mean? 1188 00:59:49,870 --> 00:59:52,570 The only methods we've talked about are get and post, 1189 00:59:52,570 --> 00:59:54,220 so maybe it's something related there. 1190 00:59:54,220 --> 00:59:56,500 Well the route in question was slash register, 1191 00:59:56,500 --> 00:59:59,230 so maybe it's something related to my register route, 1192 00:59:59,230 --> 01:00:03,430 and see if those kinds of clues can lead you to a solution like Santiago 1193 01:00:03,430 --> 01:00:04,300 just proposed. 1194 01:00:04,300 --> 01:00:07,030 Let me go ahead and restart my server. 1195 01:00:07,030 --> 01:00:10,390 Let me go ahead and reload my form, type in David again, 1196 01:00:10,390 --> 01:00:14,570 I'm going to select dodgeball, register, voila, you are registered. 1197 01:00:14,570 --> 01:00:15,070 All right. 1198 01:00:15,070 --> 01:00:16,778 I'm not actually registered for anything, 1199 01:00:16,778 --> 01:00:20,800 but I feel like there's still a missed opportunity for error checking now. 1200 01:00:20,800 --> 01:00:23,800 In fact, let me go back to my form, not type David 1201 01:00:23,800 --> 01:00:26,080 and not select dodgeball and click Register. 1202 01:00:26,080 --> 01:00:27,340 Well this is kind of stupid. 1203 01:00:27,340 --> 01:00:30,580 Like its claim, it's saying I'm registered even if I only type my name, 1204 01:00:30,580 --> 01:00:32,358 no sport, you are registered. 1205 01:00:32,358 --> 01:00:34,900 So there's a missed opportunity here for some error checking. 1206 01:00:34,900 --> 01:00:36,760 So let's at least go in and add this. 1207 01:00:36,760 --> 01:00:38,650 Let's go ahead and do something like this. 1208 01:00:38,650 --> 01:00:42,550 How about if not request dot form dot get 1209 01:00:42,550 --> 01:00:51,640 name or request dot form dot get sports, or not that, 1210 01:00:51,640 --> 01:00:56,860 then let me go ahead and return render template failure dot HTML, 1211 01:00:56,860 --> 01:00:59,592 otherwise I'll return success dot HTML. 1212 01:00:59,592 --> 01:01:00,550 So let me try this now. 1213 01:01:00,550 --> 01:01:02,560 Let me rerun the server, Flask run. 1214 01:01:02,560 --> 01:01:05,110 Let me go ahead and reload my form, no changes to the form, 1215 01:01:05,110 --> 01:01:07,660 but now if I don't cooperate and I click Register, 1216 01:01:07,660 --> 01:01:09,860 OK, now really bad things are happening. 1217 01:01:09,860 --> 01:01:11,290 This is one of those 500 errors. 1218 01:01:11,290 --> 01:01:12,580 Let's see where I screwed up. 1219 01:01:12,580 --> 01:01:16,450 Internal server error and the subsequent paragraph are not very descriptive. 1220 01:01:16,450 --> 01:01:20,560 But if I go to my terminal window, here's my exception 1221 01:01:20,560 --> 01:01:23,740 a Jinja 2 exception, that's the templating language, 1222 01:01:23,740 --> 01:01:26,160 failure dot HTML is not found. 1223 01:01:26,160 --> 01:01:28,660 All right, well that's just because I made a stupid mistake, 1224 01:01:28,660 --> 01:01:30,130 so let me stop the server. 1225 01:01:30,130 --> 01:01:33,160 Let me go ahead and copy success dot HTML for now. 1226 01:01:33,160 --> 01:01:35,240 Let me go ahead and paste it in here. 1227 01:01:35,240 --> 01:01:37,390 And I could probably factor this out, but we're 1228 01:01:37,390 --> 01:01:40,870 going to keep it simple for now and call this failure dot HTML, 1229 01:01:40,870 --> 01:01:44,590 put it in Frosh IMs templates, save it. 1230 01:01:44,590 --> 01:01:47,050 Now let me rerun my server. 1231 01:01:47,050 --> 01:01:48,550 Now let me go back. 1232 01:01:48,550 --> 01:01:53,020 Let me try not typing in anything and just registering, OK, voila. 1233 01:01:53,020 --> 01:01:54,640 Now it's actually checking. 1234 01:01:54,640 --> 01:01:58,540 And if I go back here, name, OK, I'll not type in a sport, 1235 01:01:58,540 --> 01:02:00,160 it's still not checking. 1236 01:02:00,160 --> 01:02:02,453 But there's still this kind of hack here. 1237 01:02:02,453 --> 01:02:05,620 You know, you recall from last week that if you right click or control click 1238 01:02:05,620 --> 01:02:08,530 on anything in any web page, you can inspect it 1239 01:02:08,530 --> 01:02:10,840 in Chrome or your preferred browser, and that 1240 01:02:10,840 --> 01:02:13,300 lets you start poking around the HTML. 1241 01:02:13,300 --> 01:02:16,000 And watch this, maybe I'm a little bit upset 1242 01:02:16,000 --> 01:02:19,208 that there's no, let's say, tennis. 1243 01:02:19,208 --> 01:02:22,000 Tennis is not offered by the intramural sports program, but darn it 1244 01:02:22,000 --> 01:02:23,530 I want to register for such. 1245 01:02:23,530 --> 01:02:28,560 Well, again, using a browser, there's nothing stopping me from, for instance, 1246 01:02:28,560 --> 01:02:32,470 I don't know how to do this, let's change ultimate Frisbee to tennis, 1247 01:02:32,470 --> 01:02:36,670 and literally change the HTML on the page, zoom back out, 1248 01:02:36,670 --> 01:02:41,110 close the inspector, ha, ha, now tennis is a sport at Harvard. 1249 01:02:41,110 --> 01:02:42,640 So now watch what I can do. 1250 01:02:42,640 --> 01:02:46,530 Register for tennis, type in my name David, voila, registered for tennis. 1251 01:02:46,530 --> 01:02:47,030 Right? 1252 01:02:47,030 --> 01:02:48,985 I've hacked the website. 1253 01:02:48,985 --> 01:02:50,860 All right, so in some sense I kind of sort of 1254 01:02:50,860 --> 01:02:52,433 have hacked the website this time. 1255 01:02:52,433 --> 01:02:54,850 Now obviously I'm not doing anything with this information 1256 01:02:54,850 --> 01:02:56,020 on the server at the moment. 1257 01:02:56,020 --> 01:02:58,720 I'm just blindly saying registered or not registered. 1258 01:02:58,720 --> 01:03:00,590 But notice what I've just done. 1259 01:03:00,590 --> 01:03:02,560 In fact, let's really notice what I've done. 1260 01:03:02,560 --> 01:03:06,820 Let me go ahead and inspect the page again, let me go to my network tab, 1261 01:03:06,820 --> 01:03:11,020 and let me resubmit this form, and watch what happens here. 1262 01:03:11,020 --> 01:03:16,782 Let me go back here, let me type in David, let me do this quick hack again, 1263 01:03:16,782 --> 01:03:18,490 let me go ahead and right click on sport, 1264 01:03:18,490 --> 01:03:22,210 inspect, let me get rid of ultimate Frisbee and change this to tennis 1265 01:03:22,210 --> 01:03:25,930 again, and let me change this to tennis again, enter. 1266 01:03:25,930 --> 01:03:30,250 Now let me go to my network tab, select tennis from the dropdown, 1267 01:03:30,250 --> 01:03:37,360 and then down here, let me go ahead here and click Register. 1268 01:03:37,360 --> 01:03:39,130 Notice what's going on down here. 1269 01:03:39,130 --> 01:03:42,800 Just like last week, you can see a list of all of the HTTP requests. 1270 01:03:42,800 --> 01:03:44,380 So let's look at slash register. 1271 01:03:44,380 --> 01:03:52,240 Let me now zoom in on all of this and scroll down to the form data 1272 01:03:52,240 --> 01:03:55,180 which we didn't see last week but is there for post requests. 1273 01:03:55,180 --> 01:04:00,670 I have legitimately sent from my browser David and tennis to the server. 1274 01:04:00,670 --> 01:04:03,688 The onus is now on you, the programmer, to make sure 1275 01:04:03,688 --> 01:04:06,730 that you're not actually going to let me register for tennis if it is not 1276 01:04:06,730 --> 01:04:07,930 a supported sport. 1277 01:04:07,930 --> 01:04:10,120 So now there's more error checking necessary. 1278 01:04:10,120 --> 01:04:14,417 It's not sufficient to just trust that the user typed in a name and a sport. 1279 01:04:14,417 --> 01:04:16,750 You can't just check for the absence of either of those. 1280 01:04:16,750 --> 01:04:18,667 Now, we should really be smarter and make sure 1281 01:04:18,667 --> 01:04:23,260 that whatever sport the human's browser sent actually exists at Harvard. 1282 01:04:23,260 --> 01:04:25,635 And you could imagine this going very wrong very quickly, 1283 01:04:25,635 --> 01:04:28,427 if it's a bank account, like how much money do you want to deposit? 1284 01:04:28,427 --> 01:04:31,090 Well I'll just hack the HTML and change the amount of money 1285 01:04:31,090 --> 01:04:33,070 I'm depositing or withdrawing, right? 1286 01:04:33,070 --> 01:04:37,120 You should not be able to change a server's data 1287 01:04:37,120 --> 01:04:40,240 or database by just changing some HTML. 1288 01:04:40,240 --> 01:04:45,255 You should never, ever trust your users, or myself in this case. 1289 01:04:45,255 --> 01:04:46,630 So how do we defend against this? 1290 01:04:46,630 --> 01:04:49,213 Well there's a solution to this problem that actually gives us 1291 01:04:49,213 --> 01:04:50,630 some other features as well. 1292 01:04:50,630 --> 01:04:54,220 Let me go ahead and get rid of this silliness 1293 01:04:54,220 --> 01:04:56,800 where I've literally hardcoded all of these sports 1294 01:04:56,800 --> 01:05:00,040 in the HTML, which literally I resorted to copying and pasting. 1295 01:05:00,040 --> 01:05:03,340 That should have been the first clue that we can probably do better. 1296 01:05:03,340 --> 01:05:07,150 Let me instead go into application dot py, and let me go up here, 1297 01:05:07,150 --> 01:05:09,880 and let me just define a global variable called Sports. 1298 01:05:09,880 --> 01:05:13,930 I'll capitalize it as is the convention when defining constants. 1299 01:05:13,930 --> 01:05:18,032 And let me go ahead and say, the sports are going to be this Python list. 1300 01:05:18,032 --> 01:05:20,740 So I'm going to keep it pretty and put it on multiple lines using 1301 01:05:20,740 --> 01:05:22,430 square brackets because it's a list. 1302 01:05:22,430 --> 01:05:25,690 Here's where I'm going to say dodgeball as one sport, 1303 01:05:25,690 --> 01:05:33,160 flag football was our next, comma, soccer is our third, volleyball fourth, 1304 01:05:33,160 --> 01:05:37,610 and then lastly we'll leave in ultimate Frisbee as legitimate. 1305 01:05:37,610 --> 01:05:39,310 So those are my sports. 1306 01:05:39,310 --> 01:05:42,190 How do I now use that list of sports? 1307 01:05:42,190 --> 01:05:44,530 Well, I can just pass them into my template. 1308 01:05:44,530 --> 01:05:48,670 I can say something like this: Sports, or anything, x, or y, 1309 01:05:48,670 --> 01:05:52,140 or z, but sports is more descriptive, equals sports. 1310 01:05:52,140 --> 01:05:54,570 So this is to say, I'm going to create in my template 1311 01:05:54,570 --> 01:05:56,790 a variable called sports, the value of which 1312 01:05:56,790 --> 01:05:59,850 is going to be that same global variable. 1313 01:05:59,850 --> 01:06:03,150 And to be clear, Flask requires that you choose a name. 1314 01:06:03,150 --> 01:06:06,090 You can't just pass in sports because Flask just 1315 01:06:06,090 --> 01:06:09,000 won't know what to do with a single argument like that. 1316 01:06:09,000 --> 01:06:10,860 You have to give these things names. 1317 01:06:10,860 --> 01:06:13,080 And again, it tends to lead to this redundancy 1318 01:06:13,080 --> 01:06:16,530 where you're reusing the same words, but one is your variable on the right, 1319 01:06:16,530 --> 01:06:19,870 the other is the name you're using in your template on the left. 1320 01:06:19,870 --> 01:06:22,560 So now let's do this in index dot HTML. 1321 01:06:22,560 --> 01:06:24,750 Here's where templating gets more powerful. 1322 01:06:24,750 --> 01:06:28,590 In templates like Jinja, you don't just have curly braces left and right, 1323 01:06:28,590 --> 01:06:32,400 and you don't just have the blocks with the curly braces and percent signs, 1324 01:06:32,400 --> 01:06:36,090 you even have some simple programming constructs. 1325 01:06:36,090 --> 01:06:39,490 I can actually do something like this. 1326 01:06:39,490 --> 01:06:44,250 It turns out I can actually do something like this. 1327 01:06:44,250 --> 01:06:49,642 For sport in sports, end for, so it's a little stupid, 1328 01:06:49,642 --> 01:06:51,600 the syntax, that you literally say end and then 1329 01:06:51,600 --> 01:06:54,670 the name of whatever the preposition was a moment ago, 1330 01:06:54,670 --> 01:06:57,360 but now let me go ahead and generate an option whose value is 1331 01:06:57,360 --> 01:07:01,530 quote unquote the current sport, close, that and then in here 1332 01:07:01,530 --> 01:07:03,450 let me say sport again. 1333 01:07:03,450 --> 01:07:04,560 Done. 1334 01:07:04,560 --> 01:07:09,750 Now I have used a for loop in my template, the syntax for which 1335 01:07:09,750 --> 01:07:13,200 looks almost identical to Python, that's deliberate, the authors of Jinja 1336 01:07:13,200 --> 01:07:18,000 essentially borrowed Python's own syntax so it's not too much new information 1337 01:07:18,000 --> 01:07:18,990 overload. 1338 01:07:18,990 --> 01:07:20,430 And notice what I'm doing. 1339 01:07:20,430 --> 01:07:25,740 I'm using this Jinja syntax to iterate over that Sports variable. 1340 01:07:25,740 --> 01:07:28,725 It's a for loop, so I'm saying iteratively set sport 1341 01:07:28,725 --> 01:07:31,350 equal to the first sport, then the second, then the third, then 1342 01:07:31,350 --> 01:07:32,475 the fourth, then the fifth. 1343 01:07:32,475 --> 01:07:36,090 And then inside of this block here, this for loop, 1344 01:07:36,090 --> 01:07:39,480 I'm using the double curly braces to just plug in the sport there, 1345 01:07:39,480 --> 01:07:41,010 plug in the sport there. 1346 01:07:41,010 --> 01:07:44,400 And what's amazing about this feature of Flask 1347 01:07:44,400 --> 01:07:47,010 and in turn web frameworks in general is that now when 1348 01:07:47,010 --> 01:07:53,250 I run Flask run, and I open up my URL and go to this form, voila, it's there. 1349 01:07:53,250 --> 01:07:54,930 It's dynamically generated for me. 1350 01:07:54,930 --> 01:07:57,180 And if I look at my page's source in my browser, 1351 01:07:57,180 --> 01:08:00,610 notice that all of those options are indeed there. 1352 01:08:00,610 --> 01:08:02,490 But I didn't have to type them out manually. 1353 01:08:02,490 --> 01:08:07,020 I now have it in an array and I'm dynamically generating even more HTML. 1354 01:08:07,020 --> 01:08:09,000 And what's more powerful about that savings 1355 01:08:09,000 --> 01:08:12,210 is that now I can go into my application dot py, and let's 1356 01:08:12,210 --> 01:08:14,230 not just check for this value. 1357 01:08:14,230 --> 01:08:19,649 So if not request dot form dot get name, that was saying if there is no name, 1358 01:08:19,649 --> 01:08:23,220 and then this part here was saying if there is no sport, 1359 01:08:23,220 --> 01:08:26,850 why don't I more specifically say, or the sport 1360 01:08:26,850 --> 01:08:30,930 that the user input into the form is not in sports. 1361 01:08:30,930 --> 01:08:33,359 So here's where Python gets pretty elegant. 1362 01:08:33,359 --> 01:08:36,210 Now I'm checking two Boolean expressions. 1363 01:08:36,210 --> 01:08:40,350 Is it the case that there is not a request dot form dot get name, 1364 01:08:40,350 --> 01:08:44,880 or is it the case that the sport that was in the user's form 1365 01:08:44,880 --> 01:08:49,510 is not in the global variable, sports, then it should be failure. 1366 01:08:49,510 --> 01:08:51,840 So you can send me tennis, you can send me water polo, 1367 01:08:51,840 --> 01:08:53,819 you can send me any sport you want. 1368 01:08:53,819 --> 01:08:58,170 I am now going to reject it because I am validating your submission 1369 01:08:58,170 --> 01:09:00,310 against server side data. 1370 01:09:00,310 --> 01:09:01,620 And again, this is thematic. 1371 01:09:01,620 --> 01:09:05,399 Unfortunately you can never, ever trust user input. 1372 01:09:05,399 --> 01:09:08,729 You should always assume that some annoying 1373 01:09:08,729 --> 01:09:11,850 hacker out there or friend or sibling is going 1374 01:09:11,850 --> 01:09:15,540 to be trying to hack into or crash your programs. 1375 01:09:15,540 --> 01:09:19,200 But you can defend against that by programming defensively in this way. 1376 01:09:19,200 --> 01:09:24,819 So case in point now, if I go ahead and David, dodgeball, register, that works. 1377 01:09:24,819 --> 01:09:28,500 But if I do this little hack again where I go into my HTML, 1378 01:09:28,500 --> 01:09:32,310 I go down here, I change ultimate Frisbee, for instance, 1379 01:09:32,310 --> 01:09:36,060 to tennis, and also change it here to tennis, 1380 01:09:36,060 --> 01:09:41,760 zoom out, close that, choose tennis, type in my name, David, voila. 1381 01:09:41,760 --> 01:09:42,600 Wait a minute. 1382 01:09:42,600 --> 01:09:44,130 Damn it. 1383 01:09:44,130 --> 01:09:46,069 Why did that work? 1384 01:09:46,069 --> 01:09:47,939 Oh, wait. 1385 01:09:47,939 --> 01:09:48,470 OK. 1386 01:09:48,470 --> 01:09:49,790 I didn't restart the server. 1387 01:09:49,790 --> 01:09:51,680 It was still running the old code. 1388 01:09:51,680 --> 01:09:52,642 Now I open it up. 1389 01:09:52,642 --> 01:09:53,850 Now we have to do this again. 1390 01:09:53,850 --> 01:09:54,170 OK. 1391 01:09:54,170 --> 01:09:55,880 Now I'm going to go ahead and hack the site. 1392 01:09:55,880 --> 01:09:58,760 Let me go ahead and inspect this, expand the sports, let's go ahead 1393 01:09:58,760 --> 01:10:00,770 and change ultimate Frisbee to tennis. 1394 01:10:00,770 --> 01:10:02,990 Let's go ahead and change that to tennis. 1395 01:10:02,990 --> 01:10:07,760 Close the window, change the dropdown to tennis, and now, there we go. 1396 01:10:07,760 --> 01:10:08,340 OK. 1397 01:10:08,340 --> 01:10:08,840 All right. 1398 01:10:08,840 --> 01:10:11,210 I was confused for a moment, but again, just restart the server, 1399 01:10:11,210 --> 01:10:13,400 and it will reload the changes we actually made. 1400 01:10:13,400 --> 01:10:15,942 And thank you so much, Brian, for diving in there to save me. 1401 01:10:15,942 --> 01:10:17,190 I figured it out. 1402 01:10:17,190 --> 01:10:21,350 All right, any questions or confusion beyond my own now on what it is we've 1403 01:10:21,350 --> 01:10:27,380 just done by one, dynamically generating a list of user select menu options 1404 01:10:27,380 --> 01:10:32,970 and also validating on the server against that same list of data? 1405 01:10:32,970 --> 01:10:33,840 Any questions? 1406 01:10:33,840 --> 01:10:35,370 Or anything on your end Brian? 1407 01:10:35,370 --> 01:10:36,450 BRIAN: Nothing here. 1408 01:10:36,450 --> 01:10:37,533 DAVID J. MALAN: All right. 1409 01:10:37,533 --> 01:10:41,040 So let me just demonstrate real quickly these just different user interface 1410 01:10:41,040 --> 01:10:41,670 mechanisms. 1411 01:10:41,670 --> 01:10:43,740 And suffice it to say, we're not too focused 1412 01:10:43,740 --> 01:10:46,860 for our purpose on user interface design. 1413 01:10:46,860 --> 01:10:50,400 Using a library like Bootstrap can you make these forms look much prettier 1414 01:10:50,400 --> 01:10:55,680 just by adding a few more HTML tags and a few more CSS classes, 1415 01:10:55,680 --> 01:10:58,260 but let me go ahead and make one tweak here 1416 01:10:58,260 --> 01:11:00,990 whereby we can change the UI from being the select menu 1417 01:11:00,990 --> 01:11:02,460 to a bunch of different things. 1418 01:11:02,460 --> 01:11:07,380 I index dot HTML I can go ahead and define, inside of my for loop, 1419 01:11:07,380 --> 01:11:12,240 instead of using the Select menu an input, name equals sport, 1420 01:11:12,240 --> 01:11:15,270 type equals radio for radio button, which 1421 01:11:15,270 --> 01:11:19,770 are the mutually exclusive circles that you might tick on a box, on a website, 1422 01:11:19,770 --> 01:11:22,710 and then the value of this will be this particular sport. 1423 01:11:22,710 --> 01:11:25,890 And then over here, let me go ahead outside of the radio button 1424 01:11:25,890 --> 01:11:28,680 and actually display to the human that sport name. 1425 01:11:28,680 --> 01:11:30,060 Let me restart the server. 1426 01:11:30,060 --> 01:11:33,510 Let me reload my page, and voila, we no longer have a select menu, 1427 01:11:33,510 --> 01:11:36,330 but we have radio buttons, which achieve the same result, 1428 01:11:36,330 --> 01:11:38,857 but they're just laid out in a slightly different way. 1429 01:11:38,857 --> 01:11:41,190 And they're indeed mutually exclusive like an old school 1430 01:11:41,190 --> 01:11:44,880 radio in a car where you can only select one of them at a time, 1431 01:11:44,880 --> 01:11:47,360 but otherwise the site works completely the same. 1432 01:11:47,360 --> 01:11:48,150 So which to use? 1433 01:11:48,150 --> 01:11:48,840 It depends. 1434 01:11:48,840 --> 01:11:50,910 If you've got 100 different sports you probably 1435 01:11:50,910 --> 01:11:53,010 don't want 100 different radio buttons if only 1436 01:11:53,010 --> 01:11:54,630 because they take up so much space. 1437 01:11:54,630 --> 01:11:58,675 But if instead you might want to use a drop down menu instead. 1438 01:11:58,675 --> 01:12:01,050 All right, so what's the key thing we're still not doing? 1439 01:12:01,050 --> 01:12:03,180 We've got a pretty dynamic user interface, 1440 01:12:03,180 --> 01:12:05,110 but I'm just throwing away the information 1441 01:12:05,110 --> 01:12:06,850 once the user clicks Register. 1442 01:12:06,850 --> 01:12:10,020 So let's actually start remembering, just as I did back 1443 01:12:10,020 --> 01:12:13,800 in the day, who has actually registered so that we actually have 1444 01:12:13,800 --> 01:12:16,750 a proper working registration system. 1445 01:12:16,750 --> 01:12:18,670 So how can we go about doing this? 1446 01:12:18,670 --> 01:12:21,810 Well we've seen in our look at Python in the past 1447 01:12:21,810 --> 01:12:26,670 that we can store data inside of a Python program using a list, 1448 01:12:26,670 --> 01:12:28,680 using a dictionary, using a set. 1449 01:12:28,680 --> 01:12:30,930 There's a lot of data structures that Python gives us. 1450 01:12:30,930 --> 01:12:32,025 So let's start simple. 1451 01:12:32,025 --> 01:12:33,150 And let's actually do that. 1452 01:12:33,150 --> 01:12:36,480 Let's go ahead and store our registrants maybe in a dictionary. 1453 01:12:36,480 --> 01:12:40,770 So in application dot py, which is thus far now unchanged, 1454 01:12:40,770 --> 01:12:43,590 let me give myself one other global variable, registrants, 1455 01:12:43,590 --> 01:12:45,992 and let me initialize it to an empty dictionary. 1456 01:12:45,992 --> 01:12:48,450 And recall that we did this to implement a phone book where 1457 01:12:48,450 --> 01:12:51,480 I added my name and phone number and Brian's name and phone number 1458 01:12:51,480 --> 01:12:52,620 a couple of weeks ago. 1459 01:12:52,620 --> 01:12:57,540 We used a Python dictionary to store those key value pairs, name and phone 1460 01:12:57,540 --> 01:12:58,080 number. 1461 01:12:58,080 --> 01:12:59,580 Here let's do something similar. 1462 01:12:59,580 --> 01:13:01,647 Let's store the user's name and the sport 1463 01:13:01,647 --> 01:13:03,480 for which they're registered so that we then 1464 01:13:03,480 --> 01:13:08,140 have in the computer's memory a list of all of the valid registrations. 1465 01:13:08,140 --> 01:13:10,590 So how are we going to do this and what needs to change? 1466 01:13:10,590 --> 01:13:14,040 Well let me go ahead and change this back to the Select menu 1467 01:13:14,040 --> 01:13:17,550 just because it fits on the screen a little better instead of the radio 1468 01:13:17,550 --> 01:13:18,990 buttons. 1469 01:13:18,990 --> 01:13:24,400 And from here we will have again, the user interface that we saw earlier. 1470 01:13:24,400 --> 01:13:28,200 So let me go ahead and do Flask run, let me go ahead 1471 01:13:28,200 --> 01:13:31,035 and open this up, and voila, we have that same interface 1472 01:13:31,035 --> 01:13:33,960 as before, the goal of which now is when I click Register, 1473 01:13:33,960 --> 01:13:37,470 I don't want to just naively see you are registered or you are not register, 1474 01:13:37,470 --> 01:13:39,827 I want to actually register the user. 1475 01:13:39,827 --> 01:13:41,910 So I think we're going to need to do a bit of work 1476 01:13:41,910 --> 01:13:44,730 in application dot py, the file that's actually 1477 01:13:44,730 --> 01:13:47,400 processing the user's registration. 1478 01:13:47,400 --> 01:13:50,070 So instead of just validating the form by checking 1479 01:13:50,070 --> 01:13:53,160 if they had a name or a sport that was in sports, 1480 01:13:53,160 --> 01:13:54,760 let's do something a little different. 1481 01:13:54,760 --> 01:13:57,060 So let me go ahead and sort of start anew here, 1482 01:13:57,060 --> 01:14:01,140 and let me do something like this: name equals request dot form dot get name, 1483 01:14:01,140 --> 01:14:03,930 just so I have it in a variable, it'll be a little easier to use. 1484 01:14:03,930 --> 01:14:08,250 And then let's just say if not name, then let's go ahead and return render 1485 01:14:08,250 --> 01:14:12,773 template failure dot HTML. 1486 01:14:12,773 --> 01:14:14,190 All right, let's then check sport. 1487 01:14:14,190 --> 01:14:18,660 Sport equals request dot form dot get sport, storing it in a variable 1488 01:14:18,660 --> 01:14:21,030 just so I can do this a little more cleanly. 1489 01:14:21,030 --> 01:14:27,600 And then if not sport, go ahead and return render template, template, 1490 01:14:27,600 --> 01:14:29,730 failure dot HTML. 1491 01:14:29,730 --> 01:14:31,650 And then let's do one more check, but I'm just 1492 01:14:31,650 --> 01:14:33,390 being a little more pedantic this time. 1493 01:14:33,390 --> 01:14:38,340 If sport not in sports, then let's go ahead 1494 01:14:38,340 --> 01:14:42,165 and return render template failure dot HTML. 1495 01:14:42,165 --> 01:14:44,040 But you know what, this seems a little silly. 1496 01:14:44,040 --> 01:14:47,730 If all I'm doing, if I know as the programmer what the error is, 1497 01:14:47,730 --> 01:14:50,220 but I'm just telling the user you are not registered, 1498 01:14:50,220 --> 01:14:51,720 that's not particularly good design. 1499 01:14:51,720 --> 01:14:56,200 I'm not telling the user any information about what they did wrong. 1500 01:14:56,200 --> 01:14:57,630 So let's do this instead. 1501 01:14:57,630 --> 01:15:01,380 Instead of failure dot HTML, let me go ahead and create a different file 1502 01:15:01,380 --> 01:15:03,930 called error dot HTML. 1503 01:15:03,930 --> 01:15:07,620 And this will be called error dot HTML in my Frosh IMs directory 1504 01:15:07,620 --> 01:15:11,850 in my templates directory, and in here, let's go ahead 1505 01:15:11,850 --> 01:15:18,660 and actually put an error message, for instance, something like this message. 1506 01:15:18,660 --> 01:15:22,980 So there's nothing really there other than a placeholder for message, 1507 01:15:22,980 --> 01:15:24,720 but let's see what this will do for us. 1508 01:15:24,720 --> 01:15:26,760 Let's now go back to application dot py. 1509 01:15:26,760 --> 01:15:29,880 And instead of error dot HTML, let's be a little more specific 1510 01:15:29,880 --> 01:15:32,800 and pass in an error message like missing name. 1511 01:15:32,800 --> 01:15:35,490 And down here, let's change this to error dot HTML 1512 01:15:35,490 --> 01:15:38,130 and say a message of missing sport. 1513 01:15:38,130 --> 01:15:40,370 And down here, let's change this to errors 1514 01:15:40,370 --> 01:15:46,210 dot HTML, whoops, error, error in the error, message of invalid sport. 1515 01:15:46,210 --> 01:15:49,740 So there's a sport there, but it's just not in the list of valid sports, 1516 01:15:49,740 --> 01:15:51,820 so we should tell the user accordingly. 1517 01:15:51,820 --> 01:15:55,170 So now let's just try this real quick. 1518 01:15:55,170 --> 01:15:59,500 Let's try this real quick and input this data in correctly so we can see these. 1519 01:15:59,500 --> 01:16:03,000 Let me rerun the server, reload the form, let's type in nothing 1520 01:16:03,000 --> 01:16:04,360 and just try to register. 1521 01:16:04,360 --> 01:16:04,890 OK. 1522 01:16:04,890 --> 01:16:05,640 Missing name. 1523 01:16:05,640 --> 01:16:07,890 It's more useful than just "you are not registered." 1524 01:16:07,890 --> 01:16:09,960 All right, fine, let me give you my name, David. 1525 01:16:09,960 --> 01:16:11,040 Register. 1526 01:16:11,040 --> 01:16:11,860 Missing sport. 1527 01:16:11,860 --> 01:16:12,360 OK. 1528 01:16:12,360 --> 01:16:13,860 Now let me go ahead and give you a sport. 1529 01:16:13,860 --> 01:16:16,410 And now if I registered, I'd probably get some other error 1530 01:16:16,410 --> 01:16:18,990 because I haven't handled the successful outcome yet. 1531 01:16:18,990 --> 01:16:20,430 So let's finish this up. 1532 01:16:20,430 --> 01:16:26,640 Let's go back to my application dot py in my register route 1533 01:16:26,640 --> 01:16:29,880 and then ask ourselves, well what does it mean to register the user? 1534 01:16:29,880 --> 01:16:33,300 I want to remember that the user is registered for a given 1535 01:16:33,300 --> 01:16:35,560 sport in the computer's memory. 1536 01:16:35,560 --> 01:16:38,250 And the computer's memory, recall, I'm using 1537 01:16:38,250 --> 01:16:40,852 by way of this global variable called registrants. 1538 01:16:40,852 --> 01:16:43,560 And it's all caps just to make clear that it's a global variable, 1539 01:16:43,560 --> 01:16:44,790 but that's not required. 1540 01:16:44,790 --> 01:16:50,380 And then down here, why don't I do this, registrants, name equals sport. 1541 01:16:50,380 --> 01:16:55,410 So this is very similar to what we did with names and phone numbers, keys 1542 01:16:55,410 --> 01:17:00,180 and values, where I'm using name to index into the Python dictionary, 1543 01:17:00,180 --> 01:17:02,610 and I'm setting the value equal to the sport. 1544 01:17:02,610 --> 01:17:08,160 And then let's go ahead for now and say return, render template, whoops, 1545 01:17:08,160 --> 01:17:11,940 render template, success dot HTML. 1546 01:17:11,940 --> 01:17:13,330 So let's test this out. 1547 01:17:13,330 --> 01:17:16,710 Let's go over to Frosh IMs, whoops, let's learn from my mistakes. 1548 01:17:16,710 --> 01:17:19,380 Stop the server and reload. 1549 01:17:19,380 --> 01:17:20,940 Let me go back to the browser. 1550 01:17:20,940 --> 01:17:25,350 Let me go ahead and type in David, who will register for dodgeball, register. 1551 01:17:25,350 --> 01:17:26,640 Claims it's registered. 1552 01:17:26,640 --> 01:17:29,310 Let me do Brian will register for flag football. 1553 01:17:29,310 --> 01:17:30,150 Registered. 1554 01:17:30,150 --> 01:17:31,620 He is registered. 1555 01:17:31,620 --> 01:17:35,130 But I don't know who's registered or not. 1556 01:17:35,130 --> 01:17:35,800 I don't know. 1557 01:17:35,800 --> 01:17:38,092 But you know what, let's do a little sanity check here. 1558 01:17:38,092 --> 01:17:39,810 Let me just print out registrants, right? 1559 01:17:39,810 --> 01:17:42,210 When in doubt, print or print f is your friend. 1560 01:17:42,210 --> 01:17:46,050 So let's just do a little poking around here and run Flask run again. 1561 01:17:46,050 --> 01:17:51,000 This time let's go back to the form and register David, sport, dodgeball, 1562 01:17:51,000 --> 01:17:52,720 register, same behavior. 1563 01:17:52,720 --> 01:17:54,960 But down here, notice we have this. 1564 01:17:54,960 --> 01:17:58,480 And I see a couple of you are registering as well. 1565 01:17:58,480 --> 01:18:03,660 So I see Lucas has registered for dodgeball as well, 1566 01:18:03,660 --> 01:18:05,610 Brian Y. has registered for volleyball. 1567 01:18:05,610 --> 01:18:08,425 So OK, now Harsh has registered for volleyball. 1568 01:18:08,425 --> 01:18:11,550 So this is the problem with having an internet when we do these live demos, 1569 01:18:11,550 --> 01:18:13,510 but apparently it does in fact work. 1570 01:18:13,510 --> 01:18:15,510 So let's go ahead and make this a little cleaner 1571 01:18:15,510 --> 01:18:18,870 here, and instead of just printing registrants, let's go ahead 1572 01:18:18,870 --> 01:18:20,050 and do something like this. 1573 01:18:20,050 --> 01:18:23,620 Why don't I go ahead, and you know what, let's do this. 1574 01:18:23,620 --> 01:18:30,120 Let's go ahead and render a template called registrants dot HTML. 1575 01:18:30,120 --> 01:18:33,090 And I think to make this happen, I'm going to need another route, 1576 01:18:33,090 --> 01:18:36,360 but this one will be kind of interesting in that we've never 1577 01:18:36,360 --> 01:18:40,435 dynamically generated quite this kind of success message. 1578 01:18:40,435 --> 01:18:42,810 So let me go ahead and whip something up real quick here. 1579 01:18:42,810 --> 01:18:48,930 Let me go to a new file, registrants dot HTML, Frosh IMs, templates, 1580 01:18:48,930 --> 01:18:53,040 and then in that folder, templates, and in here we're going to do 1581 01:18:53,040 --> 01:19:01,230 extends layout dot HTML, down here, block body, end block, 1582 01:19:01,230 --> 01:19:04,230 and then down here, in here, I'm going to do, this going to take me 1583 01:19:04,230 --> 01:19:06,630 a moment here, H1, registrants. 1584 01:19:06,630 --> 01:19:09,090 Then below that I'm going to give myself an HTML table. 1585 01:19:09,090 --> 01:19:10,590 Inside of the table, I'm going to define what's 1586 01:19:10,590 --> 01:19:12,780 called a table head, which is not strictly required 1587 01:19:12,780 --> 01:19:16,020 but it helps distinguish the head from the body from the optional footer. 1588 01:19:16,020 --> 01:19:18,088 Inside of here I'm going to create a table row. 1589 01:19:18,088 --> 01:19:20,130 Inside of here I'm going to create three columns, 1590 01:19:20,130 --> 01:19:22,920 using TH, table heading, which you might not have seen before. 1591 01:19:22,920 --> 01:19:26,250 Typically makes things bold by default to make clear it's the heading. 1592 01:19:26,250 --> 01:19:30,030 And I'm going to put the person's name and then another heading of their sport 1593 01:19:30,030 --> 01:19:31,110 down here. 1594 01:19:31,110 --> 01:19:35,652 And then below the table head I'm going to do tbody, which is the table body, 1595 01:19:35,652 --> 01:19:38,610 another tag you might not have seen before but just represents, indeed, 1596 01:19:38,610 --> 01:19:39,400 the body. 1597 01:19:39,400 --> 01:19:42,000 And I'm going to generate dynamically a whole bunch of TRs. 1598 01:19:42,000 --> 01:19:45,820 So for name in registrants, let's go ahead 1599 01:19:45,820 --> 01:19:51,360 in this Jinja for loop in my template and output dynamically a table row. 1600 01:19:51,360 --> 01:19:55,980 Inside of that table row, some table data, specifically the person's name, 1601 01:19:55,980 --> 01:19:58,200 and then specifically in the other column 1602 01:19:58,200 --> 01:20:04,170 the person's sport, which I can access, as we'll see by way of a variable 1603 01:20:04,170 --> 01:20:07,957 called registrants by indexing into it via the name. 1604 01:20:07,957 --> 01:20:10,290 So registrants, in a moment, is going to be a dictionary 1605 01:20:10,290 --> 01:20:12,030 that I pass into my template. 1606 01:20:12,030 --> 01:20:12,808 I think that's it. 1607 01:20:12,808 --> 01:20:14,350 It's a little tedious to type it out. 1608 01:20:14,350 --> 01:20:15,840 But notice there's no data. 1609 01:20:15,840 --> 01:20:17,970 It's only HTML and templating. 1610 01:20:17,970 --> 01:20:23,250 If I go back here now and pass in registrants equals registrants, 1611 01:20:23,250 --> 01:20:28,290 just like with the sports variable I'm providing my registrants template 1612 01:20:28,290 --> 01:20:32,750 with a variable called registrants, but again I could call it x or y or z, 1613 01:20:32,750 --> 01:20:34,830 but registrants feels a little more appropriate, 1614 01:20:34,830 --> 01:20:37,080 setting it equal to the value of that global variable, 1615 01:20:37,080 --> 01:20:40,530 thereby giving my template access to that dictionary. 1616 01:20:40,530 --> 01:20:46,530 If I now save the file, rerun Flask, go ahead back here, 1617 01:20:46,530 --> 01:20:48,810 whoops, let me go ahead and do this once more. 1618 01:20:48,810 --> 01:20:50,760 Let me go ahead and rerun Flask. 1619 01:20:50,760 --> 01:20:53,220 Let me go ahead and select my URL. 1620 01:20:53,220 --> 01:20:57,300 Let me go ahead and register David for dodgeball and click Register. 1621 01:20:57,300 --> 01:20:58,320 Voila. 1622 01:20:58,320 --> 01:20:59,370 Harsh, you beat me to it. 1623 01:20:59,370 --> 01:21:01,710 So Harsh is registered for flag football. 1624 01:21:01,710 --> 01:21:03,540 David has registered for dodgeball. 1625 01:21:03,540 --> 01:21:08,640 It's not the prettiest user interface, but if I view the page source, 1626 01:21:08,640 --> 01:21:13,060 you'll see that we indeed have the table head, followed by the table body, 1627 01:21:13,060 --> 01:21:15,810 followed by Harsh for flag football, followed by David 1628 01:21:15,810 --> 01:21:19,020 for dodgeball, and then after that any subsequent registrants 1629 01:21:19,020 --> 01:21:21,430 who are registering at the same time. 1630 01:21:21,430 --> 01:21:23,850 So this is pretty cool, I dare say, in that now we 1631 01:21:23,850 --> 01:21:28,980 have the ability to save all of these registrants to a global variable. 1632 01:21:28,980 --> 01:21:30,990 But what's a downside here? 1633 01:21:30,990 --> 01:21:33,230 We've made progress. 1634 01:21:33,230 --> 01:21:36,200 I'm now showing you users who have registered, 1635 01:21:36,200 --> 01:21:39,200 so that means the RA or proctor who's running the sport 1636 01:21:39,200 --> 01:21:40,640 knows who's registered. 1637 01:21:40,640 --> 01:21:42,320 But there's a catch. 1638 01:21:42,320 --> 01:21:45,250 What could go wrong here? 1639 01:21:45,250 --> 01:21:47,950 What's bad about using a dictionary? 1640 01:21:47,950 --> 01:21:48,792 Sophia? 1641 01:21:48,792 --> 01:21:50,750 SOPHIA: I'm assuming that every time you reload 1642 01:21:50,750 --> 01:21:54,450 the server you're just going to reset, and you're not going save the data? 1643 01:21:54,450 --> 01:21:55,450 DAVID J. MALAN: Exactly. 1644 01:21:55,450 --> 01:21:57,200 If I'm just using a global variable, it'll 1645 01:21:57,200 --> 01:22:01,150 work forever so long as the server runs forever and the IDE stays online 1646 01:22:01,150 --> 01:22:03,500 and we don't lose power or any other number of reasons. 1647 01:22:03,500 --> 01:22:06,947 But as soon as the web server, excuse me, stops or is turned off 1648 01:22:06,947 --> 01:22:09,530 or something goes wrong, we're going to lose all of that data. 1649 01:22:09,530 --> 01:22:11,770 So this is why a couple of weeks ago with Python 1650 01:22:11,770 --> 01:22:16,270 we actually used CSV files or ultimately a SQLite database. 1651 01:22:16,270 --> 01:22:17,750 But let me make one change too. 1652 01:22:17,750 --> 01:22:20,590 Because what I don't like right now is that at the moment 1653 01:22:20,590 --> 01:22:23,892 the only way to view my registrants is to actually register yourself. 1654 01:22:23,892 --> 01:22:27,100 And maybe that's a feature if you want to require people register before they 1655 01:22:27,100 --> 01:22:30,580 see who else is registered, but it feels nice to have a different route, 1656 01:22:30,580 --> 01:22:33,940 maybe slash registrants, that anyone can visit 1657 01:22:33,940 --> 01:22:36,610 to see the actual list of registrants. 1658 01:22:36,610 --> 01:22:38,870 So let me go ahead and make one tweak here. 1659 01:22:38,870 --> 01:22:44,170 Let me go ahead down here and define another route, app dot route, slash, 1660 01:22:44,170 --> 01:22:46,720 whoops, registrants. 1661 01:22:46,720 --> 01:22:48,940 And then define registrants as my function 1662 01:22:48,940 --> 01:22:50,440 but I could call it anything I want. 1663 01:22:50,440 --> 01:22:54,385 And let me actually move this rendering of template here. 1664 01:22:54,385 --> 01:22:56,260 And you know what, let me be a little clever. 1665 01:22:56,260 --> 01:23:00,850 Let me actually redirect the user to slash registrants. 1666 01:23:00,850 --> 01:23:03,640 So let me go ahead and import one more function up here, 1667 01:23:03,640 --> 01:23:06,740 redirect, from the Flask library. 1668 01:23:06,740 --> 01:23:10,780 And this is a function that will literally do one of those HTTP 301s 1669 01:23:10,780 --> 01:23:14,480 or some other status code that will send a location to the browser that says, 1670 01:23:14,480 --> 01:23:16,250 uh-uh, go here instead. 1671 01:23:16,250 --> 01:23:18,850 And the reason for this is that it's just nice now 1672 01:23:18,850 --> 01:23:22,330 that inside of my register route, once you're registered, 1673 01:23:22,330 --> 01:23:26,290 I don't need to literally copy and paste this line in two different places 1674 01:23:26,290 --> 01:23:28,660 and actually have redundant code. 1675 01:23:28,660 --> 01:23:31,420 I can just say, redirect the user to slash registrants 1676 01:23:31,420 --> 01:23:34,600 which already exists now so that they can see themselves 1677 01:23:34,600 --> 01:23:36,120 and who else has registered. 1678 01:23:36,120 --> 01:23:38,330 So if I do this again, let me restart the server. 1679 01:23:38,330 --> 01:23:43,610 Let me go back to the form, type in David for dodgeball, register. 1680 01:23:43,610 --> 01:23:47,740 OK, so Harsh, you didn't make the cut this year, this time, but we see Break 1681 01:23:47,740 --> 01:23:51,220 and Moash and David now registered in that split second, 1682 01:23:51,220 --> 01:23:52,840 amazingly, for these sports. 1683 01:23:52,840 --> 01:23:55,210 But notice the URL, which is the key point. 1684 01:23:55,210 --> 01:23:56,890 Now we're at slash registrants. 1685 01:23:56,890 --> 01:24:01,132 And if I keep reloading I'll keep seeing all of the changes since then. 1686 01:24:01,132 --> 01:24:04,090 All right, but Sophia makes a really good point in that the data is all 1687 01:24:04,090 --> 01:24:04,880 going to be lost. 1688 01:24:04,880 --> 01:24:08,780 So I think we should clean this up and maybe do one final version here, 1689 01:24:08,780 --> 01:24:14,800 where we actually save the data in, for instance, a SQLite database 1690 01:24:14,800 --> 01:24:18,570 or maybe even email it out so that we have a backup copy as well. 1691 01:24:18,570 --> 01:24:21,020 So let me go ahead and propose this. 1692 01:24:21,020 --> 01:24:27,580 Let me go ahead and propose that we make a few changes here, a few changes, 1693 01:24:27,580 --> 01:24:31,300 borrowing some inspiration from our look at both SQL and Python. 1694 01:24:31,300 --> 01:24:33,730 So I'm going to leave most of this alone for now. 1695 01:24:33,730 --> 01:24:36,370 I'm going to go ahead and get rid of this variable. 1696 01:24:36,370 --> 01:24:38,110 We'll have to store the data elsewhere. 1697 01:24:38,110 --> 01:24:42,700 And instead, let's go ahead and use a database, a SQLite database. 1698 01:24:42,700 --> 01:24:47,740 So let me go ahead and declare a database as SQL. 1699 01:24:47,740 --> 01:24:51,760 SQLite, colon slash slash slash, Frosh IMs dot db. 1700 01:24:51,760 --> 01:24:53,260 Let me go ahead and import this. 1701 01:24:53,260 --> 01:24:56,440 This, recall, is from CS50's library, this SQL library. 1702 01:24:56,440 --> 01:24:58,690 And let me go ahead in my window for just a moment 1703 01:24:58,690 --> 01:25:02,200 here and copy the database from an example I brought with me just so 1704 01:25:02,200 --> 01:25:04,250 that we don't have to create the database as well 1705 01:25:04,250 --> 01:25:08,020 and sort of rehash things from our week on SQL. 1706 01:25:08,020 --> 01:25:11,620 Let me go ahead and grab the database here, and indeed, voila, 1707 01:25:11,620 --> 01:25:13,990 the database is out of the oven. 1708 01:25:13,990 --> 01:25:18,610 And we now have a local file in my directory called Frosh IMs dot db. 1709 01:25:18,610 --> 01:25:24,490 So let's go ahead and first look at this database, SQLite of Frosh IMs dot db 1710 01:25:24,490 --> 01:25:26,440 dot schema, enter. 1711 01:25:26,440 --> 01:25:29,740 Here is the database table that I created in advance just so we 1712 01:25:29,740 --> 01:25:31,240 wouldn't have to reinvent the wheel. 1713 01:25:31,240 --> 01:25:36,160 I'm creating a table called registrants with an ID column, with a name column, 1714 01:25:36,160 --> 01:25:37,720 and a sport column. 1715 01:25:37,720 --> 01:25:40,270 The primary key is going to be that ID. 1716 01:25:40,270 --> 01:25:43,390 The textfield should not be null and the sport should not be null. 1717 01:25:43,390 --> 01:25:46,780 But we've seen all of this syntax actually in past weeks. 1718 01:25:46,780 --> 01:25:51,070 So it's just a simple table to give me an ID for every registrant, a name, 1719 01:25:51,070 --> 01:25:52,000 and a sport. 1720 01:25:52,000 --> 01:25:53,950 But I'm going to do this in Python now. 1721 01:25:53,950 --> 01:26:00,630 So let me go ahead and go back into my, let me go back into my application dot 1722 01:26:00,630 --> 01:26:04,180 py, and let's go ahead and do this. 1723 01:26:04,180 --> 01:26:07,130 When I want to actually register the user, 1724 01:26:07,130 --> 01:26:10,060 let's validate them as before, making sure 1725 01:26:10,060 --> 01:26:12,340 that they've given us their name and their sport, 1726 01:26:12,340 --> 01:26:14,020 and now let's just use a little SQL. 1727 01:26:14,020 --> 01:26:16,510 Instead of saving it into what was a global variable let's 1728 01:26:16,510 --> 01:26:22,570 do db dot execute, insert into registrants a name and a sport, 1729 01:26:22,570 --> 01:26:24,730 I don't need the ID, it will auto increment for me 1730 01:26:24,730 --> 01:26:29,140 as the primary key, and two values, question mark and question mark. 1731 01:26:29,140 --> 01:26:34,570 Again, beware SQL injection attacks, and let me pass in name and sport. 1732 01:26:34,570 --> 01:26:36,460 And I think that's all I need. 1733 01:26:36,460 --> 01:26:39,460 I'm now going to use a little bit of SQL in my Python 1734 01:26:39,460 --> 01:26:42,590 in order to insert that name and sport into the database, 1735 01:26:42,590 --> 01:26:44,270 and after that, I think I'm fine. 1736 01:26:44,270 --> 01:26:47,660 But I do need to change registrants because this variable down here no 1737 01:26:47,660 --> 01:26:48,440 longer exists. 1738 01:26:48,440 --> 01:26:51,950 But that's OK, because recall from our look at SQL in Python, 1739 01:26:51,950 --> 01:26:55,760 I can do something like this: registrants equals db dot 1740 01:26:55,760 --> 01:26:59,930 execute, select star from registrants. 1741 01:26:59,930 --> 01:27:02,570 Indeed that simple query would seem to give me access 1742 01:27:02,570 --> 01:27:05,960 to all of the registrants thus far, and now I can just pass that in like that. 1743 01:27:05,960 --> 01:27:09,980 Again, it looks a little weird that the name of your variable in your template 1744 01:27:09,980 --> 01:27:12,310 is the same as the name of this variable. 1745 01:27:12,310 --> 01:27:15,230 But again, that's because on the right is the variable, on the left 1746 01:27:15,230 --> 01:27:17,360 is the name you want to use in your template, 1747 01:27:17,360 --> 01:27:19,100 but you could call it anything you want. 1748 01:27:19,100 --> 01:27:21,350 All right, here, as always, let me cross my fingers. 1749 01:27:21,350 --> 01:27:25,730 Flask run, all right, let me go ahead and open up my URL. 1750 01:27:25,730 --> 01:27:31,550 Let me go ahead and type in David, dodgeball, register, OK, interesting. 1751 01:27:31,550 --> 01:27:33,830 So Harsh and Naveen got in there real fast, 1752 01:27:33,830 --> 01:27:36,540 again, you're just kind of waiting with the Submit button. 1753 01:27:36,540 --> 01:27:37,340 But this is a mess. 1754 01:27:37,340 --> 01:27:41,210 Something is clearly wrong now, I'm seeing like weird dictionary syntax. 1755 01:27:41,210 --> 01:27:43,890 But that's because I haven't adjusted my template. 1756 01:27:43,890 --> 01:27:48,110 So let me go into registrants dot HTML and recall 1757 01:27:48,110 --> 01:27:53,120 that when I select with select star from registrants, 1758 01:27:53,120 --> 01:27:54,830 this is like getting back rows. 1759 01:27:54,830 --> 01:27:58,130 I just renamed it to registrants, but I'm really getting back rows. 1760 01:27:58,130 --> 01:28:05,150 And rows are just dictionary, each row is a dictionary 1761 01:28:05,150 --> 01:28:07,920 of columns and the values they're in. 1762 01:28:07,920 --> 01:28:11,480 So I think my syntax just needs to change a little bit in my registrants 1763 01:28:11,480 --> 01:28:12,560 dot HTML. 1764 01:28:12,560 --> 01:28:15,920 I should really think of this as for registrant in registrants, 1765 01:28:15,920 --> 01:28:19,110 and let me go ahead and output the registrant's name. 1766 01:28:19,110 --> 01:28:23,570 And down here let me output the registrant's sport. 1767 01:28:23,570 --> 01:28:27,830 So again, this is more similar to the time we spent on SQL and Python 1768 01:28:27,830 --> 01:28:30,350 than it is to HTML and CSS right now. 1769 01:28:30,350 --> 01:28:32,820 Now I'm iterating over all of the rows. 1770 01:28:32,820 --> 01:28:35,420 And if you prefer, let's change even the semantics. 1771 01:28:35,420 --> 01:28:36,535 Let's go back over here. 1772 01:28:36,535 --> 01:28:38,660 Let's do it just like we did a couple of weeks ago. 1773 01:28:38,660 --> 01:28:43,040 Let's just get back a bunch of rows, pass in those rows to my template, 1774 01:28:43,040 --> 01:28:45,240 and now iterate over those rows. 1775 01:28:45,240 --> 01:28:49,190 And each row has a name field, and each row has a sport field. 1776 01:28:49,190 --> 01:28:51,030 So that too would be equivalent. 1777 01:28:51,030 --> 01:28:53,060 But once you understand the difference, let's 1778 01:28:53,060 --> 01:28:56,170 call it what they really are instead of this more generic row, 1779 01:28:56,170 --> 01:28:57,440 so let me revert that. 1780 01:28:57,440 --> 01:29:00,630 Now let me go ahead and rerun the code. 1781 01:29:00,630 --> 01:29:03,950 Let me try to beat everyone else to the punch, type in David for dodgeball, 1782 01:29:03,950 --> 01:29:07,015 and, Oh my god, OK, lot of people. 1783 01:29:07,015 --> 01:29:09,890 OK, new and better Harsh, all right, so you're working really quickly 1784 01:29:09,890 --> 01:29:10,850 it should seem. 1785 01:29:10,850 --> 01:29:12,840 So now we see all of the same results. 1786 01:29:12,840 --> 01:29:14,540 The database is really hopping now. 1787 01:29:14,540 --> 01:29:16,588 I'm a little nervous about scrolling any further, 1788 01:29:16,588 --> 01:29:17,880 so I'm going to leave it there. 1789 01:29:17,880 --> 01:29:20,450 But we now have a full fledged web application honestly 1790 01:29:20,450 --> 01:29:23,600 that is now much more representative of real world websites. 1791 01:29:23,600 --> 01:29:27,350 We have our own database using SQL, we have our own templates dynamically 1792 01:29:27,350 --> 01:29:29,790 generating this table even though it's ugly at the moment, 1793 01:29:29,790 --> 01:29:32,498 but I could certainly beautify it with some CSS or some Bootstrap 1794 01:29:32,498 --> 01:29:33,390 in particular. 1795 01:29:33,390 --> 01:29:36,830 But we now have a fully functioning website. 1796 01:29:36,830 --> 01:29:38,377 What would be the icing on the cake? 1797 01:29:38,377 --> 01:29:38,960 You know what? 1798 01:29:38,960 --> 01:29:41,360 It's pretty cool, even though we take it for granted 1799 01:29:41,360 --> 01:29:43,520 when a website emails you a confirmation. 1800 01:29:43,520 --> 01:29:47,420 What if we add one final feature just like I actually did years ago 1801 01:29:47,420 --> 01:29:52,970 whereby you email the registrant or yourself to report 1802 01:29:52,970 --> 01:29:54,710 that someone has actually registered? 1803 01:29:54,710 --> 01:29:56,370 So how can we go about doing this? 1804 01:29:56,370 --> 01:29:58,530 Well, let me go back into my code here. 1805 01:29:58,530 --> 01:30:00,560 And let me add one final flourish. 1806 01:30:00,560 --> 01:30:02,600 I'm going to scroll up to the top here, and I'm 1807 01:30:02,600 --> 01:30:04,370 going to import another library. 1808 01:30:04,370 --> 01:30:07,685 From Flask mail import mail and message. 1809 01:30:07,685 --> 01:30:10,310 And again, you would only know to do these things from a class, 1810 01:30:10,310 --> 01:30:12,560 from the documentation, from a tutorial or the like. 1811 01:30:12,560 --> 01:30:14,850 I looked it up in advance to see how to do this. 1812 01:30:14,850 --> 01:30:17,160 And then I have to, according to the documentation, 1813 01:30:17,160 --> 01:30:19,160 there's a bunch of initialization steps required 1814 01:30:19,160 --> 01:30:22,940 when you want to write Python code to generate emails programmatically. 1815 01:30:22,940 --> 01:30:25,000 You've got to know your username, your password, 1816 01:30:25,000 --> 01:30:26,250 and a bunch of other settings. 1817 01:30:26,250 --> 01:30:28,310 So let me go ahead and configure those now. 1818 01:30:28,310 --> 01:30:35,480 App dot config, quote unquote, mail default sender is one. 1819 01:30:35,480 --> 01:30:37,850 And I'm going to go ahead and set that equal to os 1820 01:30:37,850 --> 01:30:42,140 dot get env of mail default sender. 1821 01:30:42,140 --> 01:30:44,687 So default sender refers to a default email address. 1822 01:30:44,687 --> 01:30:47,270 So for instance, if I wanted all these emails to come from me, 1823 01:30:47,270 --> 01:30:48,510 I could do something like that. 1824 01:30:48,510 --> 01:30:51,350 But instead I'm going to store them in variables elsewhere because I 1825 01:30:51,350 --> 01:30:54,290 pre-configured my ID in advance so that no one could see my username 1826 01:30:54,290 --> 01:30:55,140 and password. 1827 01:30:55,140 --> 01:30:59,400 So I'm just going to grab some of those values from the so-called environment. 1828 01:30:59,400 --> 01:31:01,485 You won't use this feature too often but we'll 1829 01:31:01,485 --> 01:31:03,110 show it to you in the next problem set. 1830 01:31:03,110 --> 01:31:05,420 It's a way of getting access to a variable that's 1831 01:31:05,420 --> 01:31:09,710 been defined elsewhere in your IDE or in your Linux system 1832 01:31:09,710 --> 01:31:11,460 or Mac or PC more generally. 1833 01:31:11,460 --> 01:31:13,460 All right, I need to define a few more of these. 1834 01:31:13,460 --> 01:31:15,500 Let me go ahead and just do some boilerplate, 1835 01:31:15,500 --> 01:31:19,653 even though this looks like a little copy paste, which it is, 1836 01:31:19,653 --> 01:31:22,820 it is in fact necessary because there's a lot of settings for a mail server. 1837 01:31:22,820 --> 01:31:24,410 So let me do them one at a time. 1838 01:31:24,410 --> 01:31:27,560 Mail password, I don't want you to see that either, 1839 01:31:27,560 --> 01:31:33,590 so I'm going to go ahead and grab that from my environment, mail password. 1840 01:31:33,590 --> 01:31:38,570 Let's see, I need a mail port, mail port, so that's going to be 587. 1841 01:31:38,570 --> 01:31:40,790 It turns out I'm going to use Gmail, and Gmail 1842 01:31:40,790 --> 01:31:46,170 lets you send email on TCP port 587, so I looked that up in the documentation 1843 01:31:46,170 --> 01:31:46,830 too. 1844 01:31:46,830 --> 01:31:49,860 Mail server in fact will be SMTP dot gmail.com. 1845 01:31:49,860 --> 01:31:53,310 I found that on Google's documentation. 1846 01:31:53,310 --> 01:31:57,630 Mail use TLS, which is a type of encryption, 1847 01:31:57,630 --> 01:31:59,790 let me go ahead and enable that as true. 1848 01:31:59,790 --> 01:32:02,550 And then lastly mail username, I don't want 1849 01:32:02,550 --> 01:32:04,470 you to know what username I'm using, but I'm 1850 01:32:04,470 --> 01:32:07,997 going to go ahead and grab this from my environment, username. 1851 01:32:07,997 --> 01:32:09,330 And this is actually deliberate. 1852 01:32:09,330 --> 01:32:11,205 Though I'm sort of saying it tongue in cheek, 1853 01:32:11,205 --> 01:32:15,930 it is bad, bad practice to type in usernames, passwords, or anything 1854 01:32:15,930 --> 01:32:19,380 remotely private or secure into your code. 1855 01:32:19,380 --> 01:32:22,320 Because imagine if you did type your own Gmail username or password 1856 01:32:22,320 --> 01:32:24,480 into this program just to try it out literally 1857 01:32:24,480 --> 01:32:28,350 right now at home and then you can submit50 or check50, guess what? 1858 01:32:28,350 --> 01:32:31,680 You're sending your username and password to us, the staff, 1859 01:32:31,680 --> 01:32:33,720 not to mention GitHub and the whole internet, 1860 01:32:33,720 --> 01:32:35,700 by including it in your source code. 1861 01:32:35,700 --> 01:32:38,670 So while I'm sort of making fun at what I'm doing here, 1862 01:32:38,670 --> 01:32:42,840 this storing of private information in these environment variables 1863 01:32:42,840 --> 01:32:45,870 is actually best practice because it means it's not in my code, 1864 01:32:45,870 --> 01:32:49,465 I'm not going to accidentally copy and paste it elsewhere. 1865 01:32:49,465 --> 01:32:52,590 All right, I need to import one other thing which will explain all of these 1866 01:32:52,590 --> 01:32:53,760 red X's. 1867 01:32:53,760 --> 01:32:56,430 I need to also import OS. 1868 01:32:56,430 --> 01:32:59,670 So it's kind of a bold claim to import a whole operating system, 1869 01:32:59,670 --> 01:33:02,520 but there's indeed a library that comes with Python 1870 01:33:02,520 --> 01:33:06,150 called OS which gives you access to things like these environment variables 1871 01:33:06,150 --> 01:33:08,020 and others. 1872 01:33:08,020 --> 01:33:08,520 Whoo. 1873 01:33:08,520 --> 01:33:08,910 OK. 1874 01:33:08,910 --> 01:33:10,980 That was a lot, and I need one last line of code, 1875 01:33:10,980 --> 01:33:14,010 a mail variable equal to passing my Flask 1876 01:33:14,010 --> 01:33:17,830 application to a function called mail. 1877 01:33:17,830 --> 01:33:18,330 All right. 1878 01:33:18,330 --> 01:33:20,910 I think all of those errors will soon go away, 1879 01:33:20,910 --> 01:33:22,830 I think it's just being a little slow on me. 1880 01:33:22,830 --> 01:33:25,410 Let's go ahead now and actually send mail. 1881 01:33:25,410 --> 01:33:27,120 Indeed the red errors are gone. 1882 01:33:27,120 --> 01:33:31,980 Let me scroll down, and before I redirect the user to slash registrants 1883 01:33:31,980 --> 01:33:34,500 but after registering them, let me go ahead and do this. 1884 01:33:34,500 --> 01:33:37,980 Let me define a message variable equal to capital message, which 1885 01:33:37,980 --> 01:33:41,010 is the feature I imported from that library, 1886 01:33:41,010 --> 01:33:44,580 and let me create a subject line of You are registered! 1887 01:33:44,580 --> 01:33:46,560 And let me go ahead and, huh. 1888 01:33:46,560 --> 01:33:49,230 Oh, I don't actually know who to send this to, so that's OK. 1889 01:33:49,230 --> 01:33:51,010 Let's go ahead and change something here. 1890 01:33:51,010 --> 01:33:54,840 Let's go ahead and have the user ask not for their name, 1891 01:33:54,840 --> 01:33:57,600 let's ask the user for their email now. 1892 01:33:57,600 --> 01:34:02,730 So I'm going to change my actual form to ask for their email instead. 1893 01:34:02,730 --> 01:34:07,620 And now let me go back over here, and let me go back in here 1894 01:34:07,620 --> 01:34:14,410 and set a second argument of recipients equals email. 1895 01:34:14,410 --> 01:34:15,790 And let me change this here. 1896 01:34:15,790 --> 01:34:18,820 Let me go ahead and get the user's email from the form. 1897 01:34:18,820 --> 01:34:22,120 If there is no email let's yell at them and say missing email. 1898 01:34:22,120 --> 01:34:23,740 Sport is unchanged. 1899 01:34:23,740 --> 01:34:26,355 Let's go ahead and insert into registrants. 1900 01:34:26,355 --> 01:34:29,230 You know what, let's not bother inserting into the database actually. 1901 01:34:29,230 --> 01:34:30,650 Let's keep this super simple. 1902 01:34:30,650 --> 01:34:32,210 Let's get rid of the SQL stuff. 1903 01:34:32,210 --> 01:34:34,630 Let's just have it send a confirmation email. 1904 01:34:34,630 --> 01:34:35,560 So it's even simpler. 1905 01:34:35,560 --> 01:34:38,330 We'll keep the focus entirely on email here. 1906 01:34:38,330 --> 01:34:41,320 So I've created the message with a subject line and the 1907 01:34:41,320 --> 01:34:44,140 to line, so to speak, via the recipients. 1908 01:34:44,140 --> 01:34:48,790 Now I'm going to go ahead and send mail dot send message. 1909 01:34:48,790 --> 01:34:49,660 Save. 1910 01:34:49,660 --> 01:34:52,000 Here's where I'm going to cross my fingers as always. 1911 01:34:52,000 --> 01:34:54,490 I'm going to go ahead now and run this program. 1912 01:34:54,490 --> 01:34:56,980 I'm going to restart, reload my form here. 1913 01:34:56,980 --> 01:34:58,690 It's indeed asking me for email. 1914 01:34:58,690 --> 01:35:03,520 Let me go ahead and type in, let's say John Harvard's address here. 1915 01:35:03,520 --> 01:35:06,370 John Harvard, like me, will register for dodgeball, 1916 01:35:06,370 --> 01:35:08,620 and let me go and click Register. 1917 01:35:08,620 --> 01:35:14,050 Now the website is about to say internal server error, which comes as a surprise 1918 01:35:14,050 --> 01:35:16,570 to me, but let me see why. 1919 01:35:16,570 --> 01:35:19,600 Oh I accidentally am still using the database. 1920 01:35:19,600 --> 01:35:23,410 So let me fix this. 1921 01:35:23,410 --> 01:35:27,430 Let me go ahead and, since we're not using the database anymore, 1922 01:35:27,430 --> 01:35:31,360 let me go ahead and revert to our simpler return render template 1923 01:35:31,360 --> 01:35:33,040 success dot HTML. 1924 01:35:33,040 --> 01:35:33,910 All right. 1925 01:35:33,910 --> 01:35:35,120 User error. 1926 01:35:35,120 --> 01:35:38,610 Let me go ahead and restart the server. 1927 01:35:38,610 --> 01:35:41,910 OK, bad gateway, whole other problem, here we go. jharvard@cs50. 1928 01:35:41,910 --> 01:35:45,300 Let me go ahead now and register for dodgeball. 1929 01:35:45,300 --> 01:35:46,320 Register. 1930 01:35:46,320 --> 01:35:47,890 Crossing my fingers. 1931 01:35:47,890 --> 01:35:51,960 I am registered, and indeed, let's go over to my other browser 1932 01:35:51,960 --> 01:35:54,300 here where I have Gmail open. 1933 01:35:54,300 --> 01:35:58,450 I am currently masquerading as John Harvard in Gmail here. 1934 01:35:58,450 --> 01:36:02,640 Let me go ahead and refresh my inbox, and oh my god, a message from the CS50 1935 01:36:02,640 --> 01:36:05,580 bot that I am indeed registered. 1936 01:36:05,580 --> 01:36:08,430 So now we have a programmatic way of sending emails. 1937 01:36:08,430 --> 01:36:10,830 I hit it twice, so I got two emails this time. 1938 01:36:10,830 --> 01:36:17,190 But indeed I've now dynamically generated emails as well. 1939 01:36:17,190 --> 01:36:18,180 A lot. 1940 01:36:18,180 --> 01:36:22,560 But the ideas really are just based on templates 1941 01:36:22,560 --> 01:36:25,920 and the idea of sort of putting our controller logic and application dot py 1942 01:36:25,920 --> 01:36:28,800 and all of the user aesthetics and our so-called views, 1943 01:36:28,800 --> 01:36:32,460 and now that we've had a database or in some sense an email backend, 1944 01:36:32,460 --> 01:36:36,180 now we also have the notion of a model where the data is actually being stored 1945 01:36:36,180 --> 01:36:38,490 or in this case, sent. 1946 01:36:38,490 --> 01:36:41,400 Any questions or confusion or clarifications 1947 01:36:41,400 --> 01:36:50,170 here on the use of SQLites or email or any of these Frosh IMs features? 1948 01:36:50,170 --> 01:36:50,810 All right. 1949 01:36:50,810 --> 01:36:54,302 So why is there a shopping cart with cookies on the stage? 1950 01:36:54,302 --> 01:36:56,510 Well for that let's take our final five minute break. 1951 01:36:56,510 --> 01:36:58,060 We'll come back, talk about something called sessions, 1952 01:36:58,060 --> 01:37:00,520 and build even more sophisticated web apps. 1953 01:37:00,520 --> 01:37:01,390 Back in five. 1954 01:37:01,390 --> 01:37:04,330 All right, we're back, and there's one feature that we haven't really 1955 01:37:04,330 --> 01:37:07,288 fundamentally touched on at all when it comes to web programming, 1956 01:37:07,288 --> 01:37:09,580 and it's one that you and I take for granted every day, 1957 01:37:09,580 --> 01:37:13,780 any time we log into some website, buy something online, or generally interact 1958 01:37:13,780 --> 01:37:15,430 with dynamic websites. 1959 01:37:15,430 --> 01:37:18,890 And that's a feature that's generally known as sessions. 1960 01:37:18,890 --> 01:37:22,630 There is a mechanism built into web applications, whether they're 1961 01:37:22,630 --> 01:37:26,410 implemented in Flask or in other frameworks or languages that 1962 01:37:26,410 --> 01:37:29,380 allow the web servers to remember a little something about you. 1963 01:37:29,380 --> 01:37:31,960 And this is super important to how the web today works, 1964 01:37:31,960 --> 01:37:35,770 because without it you wouldn't be able to log in to Gmail or to any other site 1965 01:37:35,770 --> 01:37:38,650 and have the website remember that you are logged in. 1966 01:37:38,650 --> 01:37:40,780 Consider, after all, when you log in to Gmail, 1967 01:37:40,780 --> 01:37:44,290 you type your username, your password, maybe your two-factor authentication 1968 01:37:44,290 --> 01:37:46,150 code, and then you see your inbox. 1969 01:37:46,150 --> 01:37:49,900 And from there, you're not prompted to log in again the next time you open 1970 01:37:49,900 --> 01:37:52,120 an email and then the next time you open an email, 1971 01:37:52,120 --> 01:37:55,870 you stay logged in for some number of minutes or hours or even days 1972 01:37:55,870 --> 01:37:56,680 on your computer. 1973 01:37:56,680 --> 01:38:00,370 Even if you close the browser tab, even if you shut down your computer, 1974 01:38:00,370 --> 01:38:04,060 when you come back to Gmail quite often, you're still logged in, 1975 01:38:04,060 --> 01:38:06,940 and it remembers in some sense that you have been logged in. 1976 01:38:06,940 --> 01:38:08,870 Well, how does this actually work? 1977 01:38:08,870 --> 01:38:11,630 Well underneath the hood, anytime you visit gmail.com, 1978 01:38:11,630 --> 01:38:16,030 your browser is sending a request like this for slash, the default 1979 01:38:16,030 --> 01:38:19,753 route of gmail.com, and hopefully you're going to either see your inbox, 1980 01:38:19,753 --> 01:38:22,670 or if you're not yet logged in, you're going to see that login screen. 1981 01:38:22,670 --> 01:38:24,795 Indeed, the response is probably going to come back 1982 01:38:24,795 --> 01:38:28,120 along the lines of 200 OK, content type of text HTML, 1983 01:38:28,120 --> 01:38:30,970 and that's when you see the login form or your inbox. 1984 01:38:30,970 --> 01:38:33,580 But recall from last week there's other HTTP headers 1985 01:38:33,580 --> 01:38:36,460 that can be tucked inside of that virtual envelope that 1986 01:38:36,460 --> 01:38:40,900 provide hints to the browser and server as to how they should interoperate. 1987 01:38:40,900 --> 01:38:42,830 That's indeed what HTTP is all about. 1988 01:38:42,830 --> 01:38:46,390 It's a protocol set of conventions that govern how browsers and servers should 1989 01:38:46,390 --> 01:38:47,410 interoperate. 1990 01:38:47,410 --> 01:38:52,330 And it turns out that sometimes this server returns what are called cookies. 1991 01:38:52,330 --> 01:38:54,010 And odds are you've heard of cookies. 1992 01:38:54,010 --> 01:38:55,840 Odds are you have some sense that cookies 1993 01:38:55,840 --> 01:39:01,540 are bad or dangerous but also necessary, and indeed, all of that is true. 1994 01:39:01,540 --> 01:39:06,160 Cookies are essentially pieces of data or even files 1995 01:39:06,160 --> 01:39:08,830 that are planted on your computer or your phone 1996 01:39:08,830 --> 01:39:13,090 by a server that help them remember that you've been there before. 1997 01:39:13,090 --> 01:39:16,720 In some sense, they help remember who you are, but even websites 1998 01:39:16,720 --> 01:39:20,400 that you're not logging into very often put cookies onto your phone, 1999 01:39:20,400 --> 01:39:22,870 or your laptop or desktop which essentially might 2000 01:39:22,870 --> 01:39:26,770 be a big random number that only you are given so that even if they don't know 2001 01:39:26,770 --> 01:39:30,550 that it's Maggie who's visited the site, or Ryan, or Nicole, or someone else, 2002 01:39:30,550 --> 01:39:35,120 they know that unique identifier has been seen before. 2003 01:39:35,120 --> 01:39:37,190 And they can therefore track your behavior. 2004 01:39:37,190 --> 01:39:40,000 So if you've heard the term tracking cookies, that's all it is. 2005 01:39:40,000 --> 01:39:43,180 It's some piece of data, a big random number that's 2006 01:39:43,180 --> 01:39:47,710 been installed on your browser that your browser then remembers. 2007 01:39:47,710 --> 01:39:51,010 And the mechanism is as simple as this: one of the HTTP headers 2008 01:39:51,010 --> 01:39:53,530 that comes from server to browser literally 2009 01:39:53,530 --> 01:39:58,300 is set dash cookie, colon, then the name of a cookie, for instance session, 2010 01:39:58,300 --> 01:40:01,870 and then value, and the value might be that big random number. 2011 01:40:01,870 --> 01:40:04,420 And because of HTTP, again, it's a protocol 2012 01:40:04,420 --> 01:40:06,610 that browsers and servers speak together, 2013 01:40:06,610 --> 01:40:12,370 the browsers are designed to send that cookie back to every subsequent page 2014 01:40:12,370 --> 01:40:15,130 you visit on gmail.com or whatever server you're on. 2015 01:40:15,130 --> 01:40:18,760 In other words, when you visit gmail.com then an hour from now, 2016 01:40:18,760 --> 01:40:22,090 even after closing your tabs, or even tomorrow after going to sleep, 2017 01:40:22,090 --> 01:40:25,510 your browser is not only sending these headers, if you 2018 01:40:25,510 --> 01:40:30,040 have been given a cookie from gmail.com before, your browser sends 2019 01:40:30,040 --> 01:40:34,690 a similar header but without the word set, it says cookie, colon, 2020 01:40:34,690 --> 01:40:36,470 session equals value. 2021 01:40:36,470 --> 01:40:41,080 So unbeknownst to you, your browser is constantly reminding the server 2022 01:40:41,080 --> 01:40:42,550 that you've been there before. 2023 01:40:42,550 --> 01:40:46,000 And this is similar to the real world when you're perhaps in, 2024 01:40:46,000 --> 01:40:49,250 when you go into a club or a bar or an amusement park 2025 01:40:49,250 --> 01:40:51,190 and you go through the gates, you typically 2026 01:40:51,190 --> 01:40:53,957 are allowed back in by having your hand stamped. 2027 01:40:53,957 --> 01:40:56,290 And this way they don't have to check your tickets again 2028 01:40:56,290 --> 01:40:58,840 or your ID or the like, they just stamp your hand 2029 01:40:58,840 --> 01:41:02,180 which is a little reminder that you have been there before. 2030 01:41:02,180 --> 01:41:04,840 And so in fact, here, I've got a little stamp here. 2031 01:41:04,840 --> 01:41:08,320 If I visit a website, it's like my hand is being stamped here, 2032 01:41:08,320 --> 01:41:12,100 and my browser, by design of HTTP is supposed 2033 01:41:12,100 --> 01:41:14,860 to, every time I visit another page, click another link, 2034 01:41:14,860 --> 01:41:17,530 represent my hand just like you're going back 2035 01:41:17,530 --> 01:41:20,290 into the bar or the club or the amusement park 2036 01:41:20,290 --> 01:41:24,010 to remind the person at the door, the bouncer, that you've been there before 2037 01:41:24,010 --> 01:41:28,490 and to let you through rather than prompting you to log in again. 2038 01:41:28,490 --> 01:41:29,650 So that's what a cookie is. 2039 01:41:29,650 --> 01:41:32,860 It is like this virtual hand stamp that's put on your computer, 2040 01:41:32,860 --> 01:41:36,680 but your computer is designed to present it again and again. 2041 01:41:36,680 --> 01:41:39,940 So if you've ever wondered how sometimes you go shopping on one website 2042 01:41:39,940 --> 01:41:42,940 and then all of a sudden, creepily you're on Facebook or something else, 2043 01:41:42,940 --> 01:41:46,210 and you're seeing ads for the very thing you didn't buy on this other website, 2044 01:41:46,210 --> 01:41:47,800 that all derives from cookies. 2045 01:41:47,800 --> 01:41:50,400 Long story short, there's advertising companies 2046 01:41:50,400 --> 01:41:53,190 that Facebook and Google and others partner with that 2047 01:41:53,190 --> 01:41:58,350 put little images on the website or JavaScript files or other such files, 2048 01:41:58,350 --> 01:42:02,400 and because those ads are on different websites the cookies are shared 2049 01:42:02,400 --> 01:42:04,500 across multiple websites in some sense. 2050 01:42:04,500 --> 01:42:06,820 So it's like you are constantly presenting your hand 2051 01:42:06,820 --> 01:42:09,150 stamp to all these different third party companies, 2052 01:42:09,150 --> 01:42:14,100 and this is how they're advertising to you or even tracking you at worst. 2053 01:42:14,100 --> 01:42:18,220 As an aside, when you use incognito mode or private mode on your browser, 2054 01:42:18,220 --> 01:42:20,400 all of your cookies are temporarily thrown away. 2055 01:42:20,400 --> 01:42:22,600 You get an empty cookie jar, so to speak, 2056 01:42:22,600 --> 01:42:24,263 so that you do appear to be logged out. 2057 01:42:24,263 --> 01:42:26,430 And in fact, even in class, I've used incognito mode 2058 01:42:26,430 --> 01:42:28,560 a few times because I want to start fresh and not 2059 01:42:28,560 --> 01:42:32,670 have any of my prior clicks or our prior demos messing up future demos. 2060 01:42:32,670 --> 01:42:35,460 But the reason I was doing that was just to get rid of all cookies 2061 01:42:35,460 --> 01:42:37,650 and therefore all states. 2062 01:42:37,650 --> 01:42:40,920 So on the one hand, cookies are an incredibly important and powerful 2063 01:42:40,920 --> 01:42:44,520 mechanism, but suffice it to say, and more on this down the road, 2064 01:42:44,520 --> 01:42:49,540 they can be misused, certainly when it comes to one's privacy or security. 2065 01:42:49,540 --> 01:42:52,290 So with that said, let's focus on the good part of cookies 2066 01:42:52,290 --> 01:42:55,350 and consider how a typical website remembers that you're logged in. 2067 01:42:55,350 --> 01:42:58,020 Let's take that very simple idea and make it clear 2068 01:42:58,020 --> 01:43:00,920 that it's all within your power now with code to do this. 2069 01:43:00,920 --> 01:43:02,160 So let's start as follows. 2070 01:43:02,160 --> 01:43:04,020 I've created a new directory called login 2071 01:43:04,020 --> 01:43:06,870 just to demonstrate a program that logs people in. 2072 01:43:06,870 --> 01:43:09,900 I've got my same layout as before, and I've added one more tag. 2073 01:43:09,900 --> 01:43:13,050 It tends to be best practice to tell the browser that you're 2074 01:43:13,050 --> 01:43:14,640 using essentially Unicode. 2075 01:43:14,640 --> 01:43:17,640 This way I can have emojis and other characters in my HTML. 2076 01:43:17,640 --> 01:43:21,420 So I've added this line five which you'll see on Bootstrap's documentation 2077 01:43:21,420 --> 01:43:24,960 and other sites, so now I have sort of a good starting point for this page. 2078 01:43:24,960 --> 01:43:27,930 But there's really no content, there's just a block being defined here, 2079 01:43:27,930 --> 01:43:28,680 block body. 2080 01:43:28,680 --> 01:43:30,928 So that's just my same layout as before. 2081 01:43:30,928 --> 01:43:32,970 And indeed if I type ls you'll see an application 2082 01:43:32,970 --> 01:43:34,980 dot py and a templates folder. 2083 01:43:34,980 --> 01:43:39,270 In that templates folder for now is just layout dot HTML. 2084 01:43:39,270 --> 01:43:43,140 So let's go ahead and start writing a quick application whose purpose in life 2085 01:43:43,140 --> 01:43:46,450 is just to present the user with a form via which they can log in 2086 01:43:46,450 --> 01:43:48,880 and then remember that they are logged in. 2087 01:43:48,880 --> 01:43:51,780 So from Flask let me import Flask. 2088 01:43:51,780 --> 01:43:55,830 Let me also import the redirect function, the render template function, 2089 01:43:55,830 --> 01:43:59,610 the request variable, and now a session variable. 2090 01:43:59,610 --> 01:44:00,900 This is something new. 2091 01:44:00,900 --> 01:44:03,780 And then from Flask session, let me go ahead 2092 01:44:03,780 --> 01:44:08,460 and import session, and then down here let me do app gets Flask, 2093 01:44:08,460 --> 01:44:10,800 underscore, underscore, name. 2094 01:44:10,800 --> 01:44:13,620 And now I need a few more lines of code from documentation. 2095 01:44:13,620 --> 01:44:21,250 App dot config, open bracket, session permanent equals false, 2096 01:44:21,250 --> 01:44:25,620 and again, this is specific only to the library called Flask session 2097 01:44:25,620 --> 01:44:27,780 that I'm using, and that library is going 2098 01:44:27,780 --> 01:44:30,660 to enable hand stamps, essentially, for my application. 2099 01:44:30,660 --> 01:44:34,230 And I'm going to configure it to use literally the file system, 2100 01:44:34,230 --> 01:44:38,010 so session type equals file system, and file system 2101 01:44:38,010 --> 01:44:41,310 is just fancy speak for the hard drive or my own IDE account, 2102 01:44:41,310 --> 01:44:44,280 and this is an alternative to using a database or something 2103 01:44:44,280 --> 01:44:46,380 else like that, and then session app. 2104 01:44:46,380 --> 01:44:48,610 So this is just boilerplate, I literally copied 2105 01:44:48,610 --> 01:44:52,080 these three lines from the documentation for this library. 2106 01:44:52,080 --> 01:44:54,540 But to use this library, and this was also 2107 01:44:54,540 --> 01:44:56,940 true of the mail library a moment ago, there's 2108 01:44:56,940 --> 01:44:59,340 another file I should point out. 2109 01:44:59,340 --> 01:45:05,820 So when I am here, I should create one other file that I mentioned earlier 2110 01:45:05,820 --> 01:45:09,810 but we haven't created ourselves, this time called requirements dot text. 2111 01:45:09,810 --> 01:45:11,940 And I'm going to put this into my login directory, 2112 01:45:11,940 --> 01:45:14,820 and I'm going to require Flask for this application, 2113 01:45:14,820 --> 01:45:19,120 and I'm also going to require a library called Flask session. 2114 01:45:19,120 --> 01:45:21,590 So again, I claimed before on the slide that requirements 2115 01:45:21,590 --> 01:45:24,900 dot text is just a simple list of the requirements, the libraries you 2116 01:45:24,900 --> 01:45:25,800 want to use. 2117 01:45:25,800 --> 01:45:28,800 And there are commands you will use at the command line 2118 01:45:28,800 --> 01:45:30,390 to install those requirements. 2119 01:45:30,390 --> 01:45:32,160 You won't typically need to do this for the problem set, 2120 01:45:32,160 --> 01:45:34,440 but just so you've seen it, if you want to install 2121 01:45:34,440 --> 01:45:37,140 the requirements for a Python application, 2122 01:45:37,140 --> 01:45:39,000 you typically do a command like this. 2123 01:45:39,000 --> 01:45:42,983 Pip install dash r, requirements dot text. 2124 01:45:42,983 --> 01:45:45,150 And I'm not going to do because I did it in advance, 2125 01:45:45,150 --> 01:45:49,500 but just know that in order to install libraries, it's much easier in Python 2126 01:45:49,500 --> 01:45:51,840 than it was, for instance, in C. They tend 2127 01:45:51,840 --> 01:45:55,260 to be more easily packageable via this technology called 2128 01:45:55,260 --> 01:45:56,257 pip and things like it. 2129 01:45:56,257 --> 01:45:58,590 All right, let's go ahead and create a couple of routes. 2130 01:45:58,590 --> 01:46:03,900 App route slash def index, so just boilerplate as before, 2131 01:46:03,900 --> 01:46:08,370 and let's just go ahead and simply return render template of index dot 2132 01:46:08,370 --> 01:46:15,270 HTML by default, and then let's go ahead and create one other route, 2133 01:46:15,270 --> 01:46:19,770 app dot route slash login, and in my login route, which 2134 01:46:19,770 --> 01:46:22,410 will be governed by a login function, let me go ahead 2135 01:46:22,410 --> 01:46:25,980 and return render template login. 2136 01:46:25,980 --> 01:46:27,910 So let's keep it simple for the moment. 2137 01:46:27,910 --> 01:46:30,040 And now let me go ahead and implement this form. 2138 01:46:30,040 --> 01:46:31,950 So let me go ahead and create a file called 2139 01:46:31,950 --> 01:46:36,700 login dot HTML, whose purpose in life is just going to have my login form, 2140 01:46:36,700 --> 01:46:39,900 and what I want in that login form is just a space for the user's name. 2141 01:46:39,900 --> 01:46:41,760 In the real world, I would most certainly 2142 01:46:41,760 --> 01:46:45,048 do something like a username and a password, 2143 01:46:45,048 --> 01:46:48,090 but we're going to keep it simple, focus only on the essence of the idea, 2144 01:46:48,090 --> 01:46:50,600 and do something like just the user's name. 2145 01:46:50,600 --> 01:46:57,250 So, in login dot HTML, I'm going to extend layout dot HTML as before. 2146 01:46:57,250 --> 01:47:01,720 I'm going to have my block body, and I'm going to have my end block tag, 2147 01:47:01,720 --> 01:47:05,110 and then inside of here I'm going to have a form, the action for which 2148 01:47:05,110 --> 01:47:08,320 will be slash login, the method for which will be post. 2149 01:47:08,320 --> 01:47:11,230 I'll do best practices here, I don't want my username and password 2150 01:47:11,230 --> 01:47:16,030 in the real world being stored in people's autocomplete histories. 2151 01:47:16,030 --> 01:47:20,110 Let me do input, autocomplete equals off for good measure, autofocus 2152 01:47:20,110 --> 01:47:23,290 for convenience, name equals the user's name, 2153 01:47:23,290 --> 01:47:28,330 placeholder as before equals name, and then type equals text. 2154 01:47:28,330 --> 01:47:30,970 And then down here, input type equals submit. 2155 01:47:30,970 --> 01:47:33,700 So this is almost the same to our previous forms for registering 2156 01:47:33,700 --> 01:47:36,890 and so forth, but now I'm going to use it for login purposes. 2157 01:47:36,890 --> 01:47:37,990 So let's do a quick check. 2158 01:47:37,990 --> 01:47:41,540 Let me go back to my application, do Flask run, 2159 01:47:41,540 --> 01:47:46,690 I'm going to go ahead and open up my URL, and first error, let's see, 2160 01:47:46,690 --> 01:47:47,680 template not found. 2161 01:47:47,680 --> 01:47:49,060 OK, so that's actually expected. 2162 01:47:49,060 --> 01:47:51,700 I kind of knew I didn't create index dot HTML, 2163 01:47:51,700 --> 01:47:53,350 so I'm OK with that error for now. 2164 01:47:53,350 --> 01:47:55,808 Let me go ahead and zoom out though, because I deliberately 2165 01:47:55,808 --> 01:47:59,200 wanted to go to my slash login route because I wanted to test that first. 2166 01:47:59,200 --> 01:48:00,550 That seems to be working. 2167 01:48:00,550 --> 01:48:03,550 Now let's go ahead and create the file that doesn't exist, 2168 01:48:03,550 --> 01:48:08,950 index dot HTML, so index dot HTML, put this in my login folder in templates, 2169 01:48:08,950 --> 01:48:11,283 and I'm going to do this one pretty similarly. 2170 01:48:11,283 --> 01:48:14,200 I'm going to go ahead and copy paste just to save a bit of keystrokes, 2171 01:48:14,200 --> 01:48:17,170 but here I'm going to say, you are not logged in because I literally 2172 01:48:17,170 --> 01:48:18,730 haven't implemented that feature yet. 2173 01:48:18,730 --> 01:48:20,180 So that's pretty reasonable. 2174 01:48:20,180 --> 01:48:22,360 Let me go ahead and restart Flask. 2175 01:48:22,360 --> 01:48:26,330 Let me go to my index, and I should see, indeed, you are not logged in. 2176 01:48:26,330 --> 01:48:29,425 But if I go to login, I see my login form. 2177 01:48:29,425 --> 01:48:31,300 So let's make this a little more interactive. 2178 01:48:31,300 --> 01:48:34,330 Let me go into index dot HTML here and say, 2179 01:48:34,330 --> 01:48:40,570 you are not logged in, a href slash login, log in, period. 2180 01:48:40,570 --> 01:48:42,160 Let's create a better user interface. 2181 01:48:42,160 --> 01:48:47,570 So let me rerun Flask, let me go back to my web page, hit reload, 2182 01:48:47,570 --> 01:48:49,570 and now I have the beginnings of user interface, 2183 01:48:49,570 --> 01:48:51,610 super simple, but very similar to a website 2184 01:48:51,610 --> 01:48:53,560 where if you're presented with the web page, you're not logged in, 2185 01:48:53,560 --> 01:48:55,900 you're given a link or a button or something to log in. 2186 01:48:55,900 --> 01:48:58,240 And if I click this, it's just a simple get 2187 01:48:58,240 --> 01:49:02,590 request, which is the default for links, to slash login. 2188 01:49:02,590 --> 01:49:04,030 So we're almost there. 2189 01:49:04,030 --> 01:49:05,650 We almost have the ability to log in. 2190 01:49:05,650 --> 01:49:07,550 Let's do something with the information. 2191 01:49:07,550 --> 01:49:11,530 So let me go back to application dot py, and when the user logs in, 2192 01:49:11,530 --> 01:49:14,950 what is it I want to have happen exactly? 2193 01:49:14,950 --> 01:49:18,070 Well if they log in, first of all, I want to support multiple, 2194 01:49:18,070 --> 01:49:19,970 I want to support post here. 2195 01:49:19,970 --> 01:49:22,070 So let me do that for privacy's sake. 2196 01:49:22,070 --> 01:49:26,470 And then let me go ahead and do this. 2197 01:49:26,470 --> 01:49:31,000 If request dot method equals post, as before, 2198 01:49:31,000 --> 01:49:36,350 let's go ahead and remember that user logged in. 2199 01:49:36,350 --> 01:49:42,670 And then redirect user to slash. 2200 01:49:42,670 --> 01:49:44,900 Else let's go ahead and render the login form. 2201 01:49:44,900 --> 01:49:46,330 So I'm not done yet. 2202 01:49:46,330 --> 01:49:48,100 But this is the key idea. 2203 01:49:48,100 --> 01:49:50,630 I need to somehow remember that the user logged in. 2204 01:49:50,630 --> 01:49:51,980 So how can I do this? 2205 01:49:51,980 --> 01:49:58,510 Well, one, I can get the user's name from request dot form dot get name. 2206 01:49:58,510 --> 01:50:04,670 And I should assume that, yeah, that's OK, we won't validate that for now. 2207 01:50:04,670 --> 01:50:07,070 And what do I want to do with the user's name? 2208 01:50:07,070 --> 01:50:09,090 I want to store it in the session. 2209 01:50:09,090 --> 01:50:10,820 So what exactly is the session? 2210 01:50:10,820 --> 01:50:17,072 Well it turns out that as soon as you have this hand stamp, it's like, 2211 01:50:17,072 --> 01:50:18,530 it's kind of like a coat check too. 2212 01:50:18,530 --> 01:50:20,150 I don't mean to add too many metaphors here, 2213 01:50:20,150 --> 01:50:22,700 but in a fancy restaurant if you like hand your coat to someone, 2214 01:50:22,700 --> 01:50:24,200 they'll often put it in the closet and then 2215 01:50:24,200 --> 01:50:25,970 hand you back a number, which in some sense 2216 01:50:25,970 --> 01:50:27,942 is a little clue like this, a little hand stamp 2217 01:50:27,942 --> 01:50:29,150 so that they can line you up. 2218 01:50:29,150 --> 01:50:31,490 It probably shouldn't just be a smiley face because otherwise everyone 2219 01:50:31,490 --> 01:50:34,490 would get the same coat back, but they give you some kind of identifier, 2220 01:50:34,490 --> 01:50:39,890 and they put your coat into some hanger, a bucket, or some space in that closet. 2221 01:50:39,890 --> 01:50:42,050 So why is this relevant here? 2222 01:50:42,050 --> 01:50:44,990 Well the same is happening in the world of web browsers. 2223 01:50:44,990 --> 01:50:48,243 When you get a unique cookie, that's giving you a unique hanger. 2224 01:50:48,243 --> 01:50:50,660 I really should have thought this metaphor through before, 2225 01:50:50,660 --> 01:50:54,020 but you're given a unique hanger where all of your stuff can go, 2226 01:50:54,020 --> 01:50:56,630 including your coat, but in this case, including any variables 2227 01:50:56,630 --> 01:50:57,980 you want to remember. 2228 01:50:57,980 --> 01:51:02,510 So with that said, what I have access to thanks to Flask, 2229 01:51:02,510 --> 01:51:08,060 but really thanks to HTTP, is this special variable called session. 2230 01:51:08,060 --> 01:51:11,630 That is a special variable in that it's at the one hand, 2231 01:51:11,630 --> 01:51:15,110 on the one hand global, which means I can use it everywhere, 2232 01:51:15,110 --> 01:51:18,800 but fancy enough, it's tied to the current user. 2233 01:51:18,800 --> 01:51:22,370 So even if all of us on Zoom right now visit my URL, 2234 01:51:22,370 --> 01:51:24,890 as is kind of happening anyway, each of us 2235 01:51:24,890 --> 01:51:28,190 is getting our own copy of a variable called session. 2236 01:51:28,190 --> 01:51:31,330 And it's implemented underneath the hood by way of this cookie mechanism. 2237 01:51:31,330 --> 01:51:34,580 Each of us when you visit my application are getting a different cookie value. 2238 01:51:34,580 --> 01:51:38,040 That cookie value is like mapping to a different hanger in the closet 2239 01:51:38,040 --> 01:51:41,330 so that my data will go on this hanger, your data will go on that hanger, 2240 01:51:41,330 --> 01:51:42,090 and so forth. 2241 01:51:42,090 --> 01:51:45,173 And now I'm actually kind of proud of this metaphor that's working out OK. 2242 01:51:45,173 --> 01:51:48,530 The hanger is going to be where all of our individual data is stored. 2243 01:51:48,530 --> 01:51:49,850 What do we want to store? 2244 01:51:49,850 --> 01:51:53,000 This is simple, let's just store the user's name, 2245 01:51:53,000 --> 01:51:55,880 thereby remembering that I've logged in, or Brian's logged in, 2246 01:51:55,880 --> 01:51:59,060 or Sophia's logged in, or Ryan's logged in, or anyone else. 2247 01:51:59,060 --> 01:52:02,390 But the session global variable here that I've 2248 01:52:02,390 --> 01:52:07,040 highlighted in this very first line is going to be implemented by Flask for us 2249 01:52:07,040 --> 01:52:11,910 in such a way that each of us as users get our own version thereof. 2250 01:52:11,910 --> 01:52:15,110 So I'm going to quite simply use this as a dictionary in Python. 2251 01:52:15,110 --> 01:52:22,533 I'm going to go ahead and add to the session here the user's name as name. 2252 01:52:22,533 --> 01:52:24,200 And I don't even need this variable now. 2253 01:52:24,200 --> 01:52:26,220 Let me tighten this up just a little bit. 2254 01:52:26,220 --> 01:52:28,400 Let me go ahead and just store in the session, which 2255 01:52:28,400 --> 01:52:33,840 is like this hanger, the key of name and the value of whatever the user logged 2256 01:52:33,840 --> 01:52:34,340 in as. 2257 01:52:34,340 --> 01:52:35,960 And redirects I know how to do. 2258 01:52:35,960 --> 01:52:42,980 Let me go ahead and return redirect slash, let me get rid of my pseudocode, 2259 01:52:42,980 --> 01:52:44,270 and I think that's it. 2260 01:52:44,270 --> 01:52:48,170 That is sufficient, excuse me, to remember that a user has logged in. 2261 01:52:48,170 --> 01:52:50,370 You sort of put their name in the session, 2262 01:52:50,370 --> 01:52:54,000 but then it stands to reason that we need to check for this value. 2263 01:52:54,000 --> 01:52:56,810 So now let's improve index dot HTML, which at the moment 2264 01:52:56,810 --> 01:52:59,810 just blindly says always, you are not logged in. 2265 01:52:59,810 --> 01:53:02,850 Well let's actually make that decision, not just hard code that. 2266 01:53:02,850 --> 01:53:03,920 So let's do this. 2267 01:53:03,920 --> 01:53:09,470 If not session dot get name, this is the syntax 2268 01:53:09,470 --> 01:53:12,110 for saying if there's no name in the session, 2269 01:53:12,110 --> 01:53:16,910 then go ahead and return redirect slash login. 2270 01:53:16,910 --> 01:53:18,772 So if there's no name in the session, that 2271 01:53:18,772 --> 01:53:20,480 means you haven't given me your name yet. 2272 01:53:20,480 --> 01:53:23,210 Let me force you to by sending you to slash login. 2273 01:53:23,210 --> 01:53:26,720 Otherwise go ahead and render the template. 2274 01:53:26,720 --> 01:53:28,820 All right, well what more might I do now? 2275 01:53:28,820 --> 01:53:31,040 Well let me go into my index file here. 2276 01:53:31,040 --> 01:53:34,970 And instead of just naively hard coding this, watch what I can now do. 2277 01:53:34,970 --> 01:53:41,180 I can in here say, in Jinja syntax, not the curly braces, not the block syntax, 2278 01:53:41,180 --> 01:53:44,090 not the for loop, you can also use if conditions. 2279 01:53:44,090 --> 01:53:48,260 If session dot name exists, then I can say something like, 2280 01:53:48,260 --> 01:53:53,510 you are logged in as session dot name, period. 2281 01:53:53,510 --> 01:53:56,960 Then I might have something like a href equals slash logout. 2282 01:53:56,960 --> 01:54:00,360 Doesn't exist yet, but we can come back to that, log out. 2283 01:54:00,360 --> 01:54:04,400 Else if there is no session name, then let's assume 2284 01:54:04,400 --> 01:54:08,990 that the user is indeed not logged in and then say, you are not logged in, 2285 01:54:08,990 --> 01:54:10,260 log in. 2286 01:54:10,260 --> 01:54:13,470 So if I did this right, let me go ahead and stop the server here. 2287 01:54:13,470 --> 01:54:16,250 Let me go ahead and rerun Flask run, reload my form, 2288 01:54:16,250 --> 01:54:19,910 I still see, OK, wrong URL. 2289 01:54:19,910 --> 01:54:22,040 Let me go to index. 2290 01:54:22,040 --> 01:54:23,420 Oh no, this is right. 2291 01:54:23,420 --> 01:54:25,340 I'm on slash login, method's not allowed, 2292 01:54:25,340 --> 01:54:28,833 I think Santiago already pointed out what mistake I made earlier, 2293 01:54:28,833 --> 01:54:29,750 which I just repeated. 2294 01:54:29,750 --> 01:54:34,070 Let me go to application dot py. 2295 01:54:34,070 --> 01:54:36,530 I need to support multiple methods here. 2296 01:54:36,530 --> 01:54:41,130 I also want to support get so that I can actually render my template as needed. 2297 01:54:41,130 --> 01:54:43,940 So let me go ahead and rerun this server. 2298 01:54:43,940 --> 01:54:45,250 Here we go it's slash login. 2299 01:54:45,250 --> 01:54:46,250 And notice what happens. 2300 01:54:46,250 --> 01:54:47,300 Let me zoom in on this. 2301 01:54:47,300 --> 01:54:50,150 Let me get rid of the login and just go to slash, 2302 01:54:50,150 --> 01:54:52,038 notice that I'm immediately redirected. 2303 01:54:52,038 --> 01:54:53,330 Let's do what we did last week. 2304 01:54:53,330 --> 01:54:54,980 Let's open up the inspector. 2305 01:54:54,980 --> 01:54:56,510 Let's go to the Network tab. 2306 01:54:56,510 --> 01:55:00,860 Let's again visit slash and hit Enter, voila, notice what happens. 2307 01:55:00,860 --> 01:55:04,440 If I visit that request, zoom in on Chrome's network tab, 2308 01:55:04,440 --> 01:55:08,680 scroll down to response headers, notice that we get a 302, found, 2309 01:55:08,680 --> 01:55:12,540 which is a redirect code like 301, and the location is actually, 2310 01:55:12,540 --> 01:55:14,760 if you look over here, slash login. 2311 01:55:14,760 --> 01:55:18,240 So all the mechanics of HTTP are coming back into play. 2312 01:55:18,240 --> 01:55:22,110 All right let me go ahead and log in as David, click Submit, amazing. 2313 01:55:22,110 --> 01:55:23,820 You are logged in as David. 2314 01:55:23,820 --> 01:55:25,050 Notice what's going on. 2315 01:55:25,050 --> 01:55:28,720 I'm now at the slash route. 2316 01:55:28,720 --> 01:55:34,500 This is true, so this does not apply, so I'm actually seeing index dot HTML. 2317 01:55:34,500 --> 01:55:37,960 And notice I accidentally clicked log out, let's fix that. 2318 01:55:37,960 --> 01:55:39,670 Let's give us our logout route. 2319 01:55:39,670 --> 01:55:40,500 So here we go. 2320 01:55:40,500 --> 01:55:48,330 App dot route slash logout, def log out, and then in here I 2321 01:55:48,330 --> 01:55:50,577 need to just forget that the user has logged in. 2322 01:55:50,577 --> 01:55:52,410 And there's a few different ways to do this. 2323 01:55:52,410 --> 01:55:53,827 Let me do it the simplest for now. 2324 01:55:53,827 --> 01:55:56,430 Session name equals none. 2325 01:55:56,430 --> 01:55:59,760 Let's just change whatever your name is or my name is to none, 2326 01:55:59,760 --> 01:56:05,040 then let's return redirect back to slash. 2327 01:56:05,040 --> 01:56:06,540 So let's see what happens now. 2328 01:56:06,540 --> 01:56:08,460 Let me restart the server. 2329 01:56:08,460 --> 01:56:11,010 Let me go back to my index page. 2330 01:56:11,010 --> 01:56:15,300 Because I'm still logged in here, I'm going to go ahead and log out. 2331 01:56:15,300 --> 01:56:18,270 OK, let me go ahead and log in as Brian, for instance, submit. 2332 01:56:18,270 --> 01:56:19,500 You are logged in as Brian. 2333 01:56:19,500 --> 01:56:23,460 And notice I can reload, I can close the tab, I can reopen the tab. 2334 01:56:23,460 --> 01:56:27,660 It's all being remembered thanks to my browser representing the cookie. 2335 01:56:27,660 --> 01:56:29,340 And in fact, you can see that. 2336 01:56:29,340 --> 01:56:32,430 Let me go to inspect, let me go to the Network tab, 2337 01:56:32,430 --> 01:56:34,410 and let me reload this same page. 2338 01:56:34,410 --> 01:56:35,520 Reload. 2339 01:56:35,520 --> 01:56:37,560 Notice this response here. 2340 01:56:37,560 --> 01:56:43,320 In 200, notice that if I scroll down here to the request headers, notice 2341 01:56:43,320 --> 01:56:46,290 that my browser is requesting, oops, sorry, 2342 01:56:46,290 --> 01:56:50,670 notice that my browser is requesting slash, but notice if I scroll down, 2343 01:56:50,670 --> 01:56:55,335 down, down, nope, there we go, down, down, down, notice, unbeknownst to me 2344 01:56:55,335 --> 01:56:57,210 and unbeknownst to you perhaps all this time, 2345 01:56:57,210 --> 01:57:01,140 my browser is also presenting the hand stamp and saying my cookie value 2346 01:57:01,140 --> 01:57:04,581 is session equals 35456 dot, dot, dot. 2347 01:57:04,581 --> 01:57:07,710 Generally speaking it's bad to tell other people your sessions because now 2348 01:57:07,710 --> 01:57:10,002 you could all hijack my session by pretending to be me, 2349 01:57:10,002 --> 01:57:12,127 but of course this application doesn't do anything. 2350 01:57:12,127 --> 01:57:14,520 But don't do this with accounts that you care about. 2351 01:57:14,520 --> 01:57:17,170 No one should be seeing your cookie values. 2352 01:57:17,170 --> 01:57:20,640 So we actually see the cookie there, and it came from the server 2353 01:57:20,640 --> 01:57:24,320 the very first time I visited. 2354 01:57:24,320 --> 01:57:29,510 All right, any questions on that there? 2355 01:57:29,510 --> 01:57:31,820 BRIAN: Does the cookie just exist forever, 2356 01:57:31,820 --> 01:57:33,403 or is there a time when it disappears? 2357 01:57:33,403 --> 01:57:34,653 DAVID J. MALAN: Good question. 2358 01:57:34,653 --> 01:57:37,130 Does the cookie live forever or is there a time limit? 2359 01:57:37,130 --> 01:57:38,790 It depends on how you configure it. 2360 01:57:38,790 --> 01:57:41,480 So this cookie will have a default time limit 2361 01:57:41,480 --> 01:57:45,440 of some number of minutes or hours or days, after which it will expire 2362 01:57:45,440 --> 01:57:47,660 unless the server refreshes it for me. 2363 01:57:47,660 --> 01:57:49,852 You can, though, set cookies that do last forever, 2364 01:57:49,852 --> 01:57:53,060 which you probably don't want to do for the notion of logging in because odds 2365 01:57:53,060 --> 01:57:54,852 are all of us have accidentally walked away 2366 01:57:54,852 --> 01:57:58,490 from like a lab computer or a friend's computer, forgotten to log out. 2367 01:57:58,490 --> 01:58:00,920 It's at least nice to know that eventually I'll 2368 01:58:00,920 --> 01:58:03,050 be logged out automatically from this site, 2369 01:58:03,050 --> 01:58:06,320 and that's what's called a session cookie, one that eventually expires. 2370 01:58:06,320 --> 01:58:08,270 But it's also useful when you visit websites, 2371 01:58:08,270 --> 01:58:11,450 you notice that some websites have those buttons that say remember me, 2372 01:58:11,450 --> 01:58:12,680 or something like that. 2373 01:58:12,680 --> 01:58:15,230 Well you can actually set permanent cookies that don't just 2374 01:58:15,230 --> 01:58:17,780 store some random value on your computer, 2375 01:58:17,780 --> 01:58:20,510 they actually store some piece of information 2376 01:58:20,510 --> 01:58:23,150 that gets prefilled into forms subsequently. 2377 01:58:23,150 --> 01:58:26,182 And this is useful to remember your preferred settings for a website 2378 01:58:26,182 --> 01:58:27,890 if you've customized something, if you're 2379 01:58:27,890 --> 01:58:30,590 in night mode or day mode or something like that, 2380 01:58:30,590 --> 01:58:32,390 it can remember those kinds of settings. 2381 01:58:32,390 --> 01:58:36,380 And even CS50's website remembers what your selection was. 2382 01:58:36,380 --> 01:58:38,510 When you log in to some of CS50's websites, 2383 01:58:38,510 --> 01:58:41,810 you'll sometimes see a login prompt for Harvard or Yale. 2384 01:58:41,810 --> 01:58:45,320 And if you've never noticed, I regret this because we put a lot of effort 2385 01:58:45,320 --> 01:58:48,080 into this, it remembers if you used Harvard last time 2386 01:58:48,080 --> 01:58:51,140 or used Yale last time so you don't have to constantly interact 2387 01:58:51,140 --> 01:58:54,170 with the dropdown, it just remembers your implied preference. 2388 01:58:54,170 --> 01:58:55,730 We do that using cookies. 2389 01:58:55,730 --> 01:58:58,880 And so as an at home exercise if of interest, truly do start 2390 01:58:58,880 --> 01:59:02,900 opening the browser's network tab, start looking at those headers, 2391 01:59:02,900 --> 01:59:06,470 and you can begin to infer how all of today's websites work. 2392 01:59:06,470 --> 01:59:09,290 And in fact it's becoming increasingly a challenge 2393 01:59:09,290 --> 01:59:12,620 to implement things with cookies because long story short, a lot of the browser 2394 01:59:12,620 --> 01:59:15,980 manufacturers are finally starting to disable what are called third party 2395 01:59:15,980 --> 01:59:20,240 cookies, those sort of advertising style cookies that come from other servers, 2396 01:59:20,240 --> 01:59:24,320 not gmail.com, not Facebook.com, but other servers that are all too often 2397 01:59:24,320 --> 01:59:27,020 used to track people. 2398 01:59:27,020 --> 01:59:30,500 But recently, especially in the EU and now more recently in the US, 2399 01:59:30,500 --> 01:59:33,230 if you've ever had to click boxes saying I accept cookies, 2400 01:59:33,230 --> 01:59:36,140 I accept the necessary cookies, and so forth, honestly this 2401 01:59:36,140 --> 01:59:39,170 is sort of a nice idea, but it's also a little silly in 2402 01:59:39,170 --> 01:59:43,580 that now the world is just conditioning you and me to just constantly click 2403 01:59:43,580 --> 01:59:45,750 these boxes without really thinking of it. 2404 01:59:45,750 --> 01:59:48,290 But what you're really doing is granting permission 2405 01:59:48,290 --> 01:59:53,450 when you click those boxes to allow your hand to be stamped. 2406 01:59:53,450 --> 01:59:55,520 All right, any questions then on cookies, 2407 01:59:55,520 --> 02:00:01,140 or on how we've gone about implementing this login mechanism? 2408 02:00:01,140 --> 02:00:03,270 Seeing anything on your end Brian? 2409 02:00:03,270 --> 02:00:04,560 BRIAN: Nothing else here. 2410 02:00:04,560 --> 02:00:07,060 DAVID J. MALAN: All right, well let me go ahead and do this. 2411 02:00:07,060 --> 02:00:09,600 Let me go ahead and get ready an example that we 2412 02:00:09,600 --> 02:00:13,020 made in advance that will allow us to explore 2413 02:00:13,020 --> 02:00:16,830 a full-fledged e-commerce website, a store of some sort. 2414 02:00:16,830 --> 02:00:19,080 And we'll call this literally Store and this time 2415 02:00:19,080 --> 02:00:21,330 rather than write things from scratch, let me go ahead 2416 02:00:21,330 --> 02:00:24,630 and open things in my browser from a directory called store. 2417 02:00:24,630 --> 02:00:27,420 So this is available as always on the course's website. 2418 02:00:27,420 --> 02:00:31,260 And let me go ahead here and into store, let me go ahead 2419 02:00:31,260 --> 02:00:34,545 and open up application dot py, requirements 2420 02:00:34,545 --> 02:00:40,710 dot text, and my templates, including layout, books, and cart. 2421 02:00:40,710 --> 02:00:43,110 So this is a good exercise in honestly reading 2422 02:00:43,110 --> 02:00:45,450 someone else's sizable amount of code. 2423 02:00:45,450 --> 02:00:46,522 It's a few files. 2424 02:00:46,522 --> 02:00:49,230 How do you even begin when you've downloaded a program like this, 2425 02:00:49,230 --> 02:00:52,170 when you've downloaded distribution code for CS50 or any other course, 2426 02:00:52,170 --> 02:00:54,045 how do you begin to wrap your mind around it? 2427 02:00:54,045 --> 02:00:56,400 Well again, if you understand what the roles are 2428 02:00:56,400 --> 02:00:59,610 played by these different files, application dot py is your controller, 2429 02:00:59,610 --> 02:01:02,580 anything ending in dot HTML and templates is a view, 2430 02:01:02,580 --> 02:01:04,800 you can begin to sort of follow the breadcrumbs 2431 02:01:04,800 --> 02:01:07,440 and figure out what does what in these files. 2432 02:01:07,440 --> 02:01:09,780 So let's start with application dot py. 2433 02:01:09,780 --> 02:01:13,410 Notice I'm importing CS50's library, a bunch of Flask functionality, 2434 02:01:13,410 --> 02:01:14,880 including session support. 2435 02:01:14,880 --> 02:01:17,790 Below that I'm initializing the application as I've done before, 2436 02:01:17,790 --> 02:01:20,280 and below that I'm connecting to a database which 2437 02:01:20,280 --> 02:01:24,150 contains a whole bunch of products in a store, books in this case. 2438 02:01:24,150 --> 02:01:26,230 I then configure sessions, and we just did that, 2439 02:01:26,230 --> 02:01:28,120 so that code is the same as before. 2440 02:01:28,120 --> 02:01:31,320 And I think we can begin to infer what this website's going to do. 2441 02:01:31,320 --> 02:01:34,810 So my default slash route has an index function, 2442 02:01:34,810 --> 02:01:38,220 and it looks like there's a table in that database called books, 2443 02:01:38,220 --> 02:01:41,070 so I'm selecting star from books to get me all the books. 2444 02:01:41,070 --> 02:01:44,010 And then it looks like I'm rendering a template called books dot HTML, 2445 02:01:44,010 --> 02:01:45,690 and I'm passing in those books. 2446 02:01:45,690 --> 02:01:50,830 So let's follow the breadcrumbs here and go into books dot HTML. 2447 02:01:50,830 --> 02:01:54,000 It looks like books dot HTML extends layout dot HTML. 2448 02:01:54,000 --> 02:01:56,610 All right, let's look at layout dot HTML. 2449 02:01:56,610 --> 02:01:59,953 Nothing really interesting going on there, just the boilerplate placeholder 2450 02:01:59,953 --> 02:02:01,120 code that we've seen before. 2451 02:02:01,120 --> 02:02:03,787 So I'm going to close that and assume that it's not interesting. 2452 02:02:03,787 --> 02:02:04,900 Been there, done that. 2453 02:02:04,900 --> 02:02:07,830 But books dot HTML, if we continue further, is a little juicy. 2454 02:02:07,830 --> 02:02:12,540 We've got my block body between lines 3 and 14. 2455 02:02:12,540 --> 02:02:16,930 In there I've got a H1 tag just saying books at the top of the page. 2456 02:02:16,930 --> 02:02:19,860 And then I've got a for loop in my template, 2457 02:02:19,860 --> 02:02:24,690 again using Jinja syntax, that has below that an H2 with apparently 2458 02:02:24,690 --> 02:02:28,410 the title of a book, and then below that, a form, 2459 02:02:28,410 --> 02:02:30,510 and I haven't seen all of these features before, 2460 02:02:30,510 --> 02:02:34,980 like I'm not sure yet what hidden means, but notice that I do recognize a Submit 2461 02:02:34,980 --> 02:02:37,080 button that has a value of add to cart. 2462 02:02:37,080 --> 02:02:41,010 So it sounds like we're implementing a shopping catalog for like an amazon.com 2463 02:02:41,010 --> 02:02:43,200 or some kind of bookstore online. 2464 02:02:43,200 --> 02:02:46,290 All right, so now let's go back to application dot py, 2465 02:02:46,290 --> 02:02:47,880 and let's look in cart. 2466 02:02:47,880 --> 02:02:50,662 It looks like cart supports both get and post, all right, 2467 02:02:50,662 --> 02:02:53,370 so maybe I'm using the same route to handle two different things, 2468 02:02:53,370 --> 02:02:54,820 and we've seen that before. 2469 02:02:54,820 --> 02:02:57,220 The function is called cart, which makes sense. 2470 02:02:57,220 --> 02:03:00,260 This thing, let's come back to this, just to initialize our session, 2471 02:03:00,260 --> 02:03:01,260 we'll come back to that. 2472 02:03:01,260 --> 02:03:03,720 And it looks like there's not much more to this program. 2473 02:03:03,720 --> 02:03:07,380 If get is the verb, let's focus on the bottom 2474 02:03:07,380 --> 02:03:10,590 first, so let's ignore the if condition, what am I doing? 2475 02:03:10,590 --> 02:03:17,160 Selecting star from books where the ID of the book is in this list of books. 2476 02:03:17,160 --> 02:03:19,350 Well, where is this list of books coming from? 2477 02:03:19,350 --> 02:03:21,120 Session, quote unquote, cart. 2478 02:03:21,120 --> 02:03:26,670 So in the last example I used the session to store your name and my name 2479 02:03:26,670 --> 02:03:29,100 and everyone's name on a per user basis. 2480 02:03:29,100 --> 02:03:31,710 Now I'm using it to store what we'll call a shopping cart. 2481 02:03:31,710 --> 02:03:34,168 And indeed, this is the reason why there's a shopping cart, 2482 02:03:34,168 --> 02:03:36,280 thanks to our friends at the theater, on stage. 2483 02:03:36,280 --> 02:03:38,520 This is how shopping carts are implemented 2484 02:03:38,520 --> 02:03:41,760 on websites, via cookies underneath the hood 2485 02:03:41,760 --> 02:03:46,230 to give you the illusion of user specific variables, dictionaries 2486 02:03:46,230 --> 02:03:48,310 that you can store anything you want in there. 2487 02:03:48,310 --> 02:03:52,560 So it looks like my session cart key is going 2488 02:03:52,560 --> 02:03:55,463 to have a value equal to the IDs of a whole bunch of books. 2489 02:03:55,463 --> 02:03:57,630 I don't know how they're there yet, but let's assume 2490 02:03:57,630 --> 02:03:59,100 that's what I'm interpreting. 2491 02:03:59,100 --> 02:04:02,340 And then down here, I'm just rendering a template called cart dot HTML, 2492 02:04:02,340 --> 02:04:06,010 passing in the books from the database. 2493 02:04:06,010 --> 02:04:07,870 So how do they get into the session? 2494 02:04:07,870 --> 02:04:10,920 Well, if the user submits the form to the cart, 2495 02:04:10,920 --> 02:04:12,870 I think this code is now relevant. 2496 02:04:12,870 --> 02:04:16,920 If the user posts to slash cart, it looks 2497 02:04:16,920 --> 02:04:20,880 like I'm going to get the ID that they've typed in maybe? 2498 02:04:20,880 --> 02:04:21,630 Maybe? 2499 02:04:21,630 --> 02:04:24,270 And if there is in fact an ID, and it's not none, 2500 02:04:24,270 --> 02:04:26,340 it's not the default value of none, I'm going 2501 02:04:26,340 --> 02:04:31,440 to go ahead and append to the cart the ID of that book, 2502 02:04:31,440 --> 02:04:33,750 and then I'm going to redirect the user to cart. 2503 02:04:33,750 --> 02:04:36,210 So I think that's enough complexity that I think it's time 2504 02:04:36,210 --> 02:04:37,960 to look at what's actually going on. 2505 02:04:37,960 --> 02:04:40,110 So let me go ahead and do exactly that. 2506 02:04:40,110 --> 02:04:42,720 Let me scroll up and run Flask run. 2507 02:04:42,720 --> 02:04:44,940 Let me go ahead and open my URL. 2508 02:04:44,940 --> 02:04:47,220 OK, it's not the prettiest of website, but it 2509 02:04:47,220 --> 02:04:50,880 looks like my database has like all seven Harry Potter books in it, 2510 02:04:50,880 --> 02:04:54,030 and notice that each of them has a button, add to cart, add to cart, 2511 02:04:54,030 --> 02:04:54,840 add to cart. 2512 02:04:54,840 --> 02:04:57,030 Let's look at the HTML source to see what 2513 02:04:57,030 --> 02:04:59,580 my books dot HTML template generated. 2514 02:04:59,580 --> 02:05:00,710 Kind of interesting. 2515 02:05:00,710 --> 02:05:03,420 So there's that H1 books at the top. 2516 02:05:03,420 --> 02:05:06,560 Here's the first of my H2s with the title of the book. 2517 02:05:06,560 --> 02:05:10,260 Notice that there is this funky symbol here because it's like a curly quote, 2518 02:05:10,260 --> 02:05:13,030 so this is one of those HTML entities that lets you output symbols 2519 02:05:13,030 --> 02:05:15,130 that you couldn't type easily on your keyboard. 2520 02:05:15,130 --> 02:05:17,980 Here's my first form that I dynamically outputted. 2521 02:05:17,980 --> 02:05:20,380 And I claimed earlier that I didn't know what hidden was, 2522 02:05:20,380 --> 02:05:21,970 but it does what it says. 2523 02:05:21,970 --> 02:05:25,090 It allows you to submit a piece of data in a form that 2524 02:05:25,090 --> 02:05:26,810 is visually hidden from the user. 2525 02:05:26,810 --> 02:05:29,800 It's not a text box that they can type into but it is there. 2526 02:05:29,800 --> 02:05:33,880 And what's cool about this is that notice I gave it a value of 1. 2527 02:05:33,880 --> 02:05:35,920 But in this form I gave that hidden field 2528 02:05:35,920 --> 02:05:38,730 a value of 2, down here a value of 3. 2529 02:05:38,730 --> 02:05:40,120 Well, why is that? 2530 02:05:40,120 --> 02:05:47,140 Let me go into my IDE for just a moment, let me run SQLite on my store dot db, 2531 02:05:47,140 --> 02:05:51,280 let me show you with dot schema that inside of this database 2532 02:05:51,280 --> 02:05:55,510 is a books table, each of which has an ID, a title, and that's it. 2533 02:05:55,510 --> 02:06:00,582 Let me do select star from books using SQLite 3, and voila, 2534 02:06:00,582 --> 02:06:02,290 you see not only the titles of the books, 2535 02:06:02,290 --> 02:06:07,750 but a unique ID numbered aptly according to the order in which they came out, 2536 02:06:07,750 --> 02:06:09,920 as a coincidence, but intentional. 2537 02:06:09,920 --> 02:06:15,550 And so now down here, let me go ahead and move my terminal down a little bit 2538 02:06:15,550 --> 02:06:16,370 here. 2539 02:06:16,370 --> 02:06:21,850 Let me go ahead and rerun Flask run, and if I now submit one of these forms, 2540 02:06:21,850 --> 02:06:22,840 let's see what happens. 2541 02:06:22,840 --> 02:06:25,150 Add to cart the first book. 2542 02:06:25,150 --> 02:06:25,930 Interesting. 2543 02:06:25,930 --> 02:06:29,610 I've been redirected to slash cart, and notice I have an ordered list, 2544 02:06:29,610 --> 02:06:32,530 an OL tag, it would seem, with that first book. 2545 02:06:32,530 --> 02:06:34,100 Let me go back to the catalog. 2546 02:06:34,100 --> 02:06:35,600 Prisoner of Azkaban was pretty good. 2547 02:06:35,600 --> 02:06:36,790 Let's add that to cart. 2548 02:06:36,790 --> 02:06:37,940 Now I see this here. 2549 02:06:37,940 --> 02:06:40,000 And notice this, if I reload, reload, I don't 2550 02:06:40,000 --> 02:06:43,000 know why I'm holding up my hand because I'm clearly using my other hand, 2551 02:06:43,000 --> 02:06:45,100 but I'm reloading the page again and again, 2552 02:06:45,100 --> 02:06:48,280 and it's showing me exactly what is in my cart. 2553 02:06:48,280 --> 02:06:49,690 So where is this coming from? 2554 02:06:49,690 --> 02:06:55,090 Well, if we go back to our code, this logic here under the post condition 2555 02:06:55,090 --> 02:07:02,687 is adding the ID, book number one, book number three, to my session's cart key. 2556 02:07:02,687 --> 02:07:04,270 Now where did that cart key come from? 2557 02:07:04,270 --> 02:07:06,880 This is the only other piece I proposed we come back to. 2558 02:07:06,880 --> 02:07:09,940 I just need some way at the top of my code to initialize the cart. 2559 02:07:09,940 --> 02:07:13,720 And long story short, there's not going to be a key called cart in the session 2560 02:07:13,720 --> 02:07:17,620 unless you put it there, like Flask doesn't come with name or cart. 2561 02:07:17,620 --> 02:07:18,980 You have to put it there. 2562 02:07:18,980 --> 02:07:22,610 So notice if cart, quote unquote, is not yet in my session, 2563 02:07:22,610 --> 02:07:26,000 I'm just initializing it to an empty Python list. 2564 02:07:26,000 --> 02:07:28,000 And I could use a set, I could use a dictionary, 2565 02:07:28,000 --> 02:07:29,167 I could use anything I want. 2566 02:07:29,167 --> 02:07:31,390 I chose to keep it simple with a list, but that's 2567 02:07:31,390 --> 02:07:33,795 how I'm remembering what's in my cart. 2568 02:07:33,795 --> 02:07:36,670 And unlike all of our previous examples, because I see a bunch of you 2569 02:07:36,670 --> 02:07:39,790 are now trying to add things to your own cart, each of us 2570 02:07:39,790 --> 02:07:41,560 is seeing different shopping carts. 2571 02:07:41,560 --> 02:07:43,780 We all have different things in our shopping cart. 2572 02:07:43,780 --> 02:07:46,905 If I keep reloading, doesn't matter how many of you are trying to add books 2573 02:07:46,905 --> 02:07:50,680 to your cart, you're only adding them literally to your cart 2574 02:07:50,680 --> 02:07:55,777 and not mine because we all have different stamps on our hand. 2575 02:07:55,777 --> 02:07:58,610 All right, so here too I would encourage you when you, next time you 2576 02:07:58,610 --> 02:08:00,920 go on Amazon and add some things to your cart, 2577 02:08:00,920 --> 02:08:03,710 like literally, that is all that's happening underneath the hood. 2578 02:08:03,710 --> 02:08:05,240 And Amazon surely has other features, you 2579 02:08:05,240 --> 02:08:08,532 can change quantities, which is kind of nice, you can add things to wish lists, 2580 02:08:08,532 --> 02:08:11,450 which is nice, but all of that, if you start looking at the HTML, 2581 02:08:11,450 --> 02:08:14,643 and you look at the network request going back and forth, all of those 2582 02:08:14,643 --> 02:08:17,060 features that we just take for granted these days are just 2583 02:08:17,060 --> 02:08:21,560 built on very simple, well, relatively simple HTML 2584 02:08:21,560 --> 02:08:24,913 forms and these inputs and these buttons and on the server, these sessions. 2585 02:08:24,913 --> 02:08:27,830 And Amazon might be using a different language, a different framework, 2586 02:08:27,830 --> 02:08:29,390 but all of these ideas are the same. 2587 02:08:29,390 --> 02:08:32,557 And so indeed this week is not about teaching you Flask which in a few years 2588 02:08:32,557 --> 02:08:34,230 time will probably be irrelevant. 2589 02:08:34,230 --> 02:08:37,550 It's about teaching these ideas and principles of these HTTP requests 2590 02:08:37,550 --> 02:08:40,580 and responses, these cookies, these sessions, and the features 2591 02:08:40,580 --> 02:08:43,820 that we can therefore build on top of them. 2592 02:08:43,820 --> 02:08:47,330 All right, I think we have time for one final example that 2593 02:08:47,330 --> 02:08:50,870 will now bring back our old friend JavaScript from last week. 2594 02:08:50,870 --> 02:08:55,070 Up until now, we have been using Python on the server 2595 02:08:55,070 --> 02:08:59,060 to generate dynamically HTML, and even though my designs today 2596 02:08:59,060 --> 02:09:02,060 have been hideous, you could certainly imagine adding CSS to them 2597 02:09:02,060 --> 02:09:04,850 some, classes, some Bootstrap, just a pretty things up like 2598 02:09:04,850 --> 02:09:09,860 the forms especially, but that's not anything new versus last week. 2599 02:09:09,860 --> 02:09:12,983 But last week we did have JavaScript as a programming language, 2600 02:09:12,983 --> 02:09:14,900 but it was a client side programming language, 2601 02:09:14,900 --> 02:09:16,490 at least in our usage thereof. 2602 02:09:16,490 --> 02:09:18,770 It was a way of getting the user's browsers 2603 02:09:18,770 --> 02:09:22,790 to run code, conditions, and functions, and loops, and so forth on the browser 2604 02:09:22,790 --> 02:09:23,720 not on the server. 2605 02:09:23,720 --> 02:09:26,510 Today, we've introduced Python again, so we have now the ability 2606 02:09:26,510 --> 02:09:29,390 to do something on the server, and where the web gets 2607 02:09:29,390 --> 02:09:32,210 really interesting these days is when we marry 2608 02:09:32,210 --> 02:09:34,970 the so-called front end that the user sees 2609 02:09:34,970 --> 02:09:37,280 and the backend which is the server. 2610 02:09:37,280 --> 02:09:39,530 The front end is the user interface you and I interact 2611 02:09:39,530 --> 02:09:42,260 with, the backend is the Python code, the SQL code 2612 02:09:42,260 --> 02:09:45,560 that the humans never see but you, the programmer, see. 2613 02:09:45,560 --> 02:09:52,240 So what can we do to combine these two components, ultimately, 2614 02:09:52,240 --> 02:09:53,530 front end and backend? 2615 02:09:53,530 --> 02:09:55,990 Well let's do something like this. 2616 02:09:55,990 --> 02:10:00,820 Let's bring back our old database of shows, and let me go ahead 2617 02:10:00,820 --> 02:10:03,070 and show you quickly what's in this folder here. 2618 02:10:03,070 --> 02:10:08,530 In shows we have SQLite 3 shows dot db, a smaller version 2619 02:10:08,530 --> 02:10:10,300 of what we played with a few weeks back. 2620 02:10:10,300 --> 02:10:12,400 I've whittled this down just for size's sake 2621 02:10:12,400 --> 02:10:17,247 to have only the names, only the IDs of TV shows and the titles of TV shows 2622 02:10:17,247 --> 02:10:17,830 and that's it. 2623 02:10:17,830 --> 02:10:20,913 I threw away the ratings and the writers and the directors and all of that 2624 02:10:20,913 --> 02:10:22,750 just to keep the focus only on the titles 2625 02:10:22,750 --> 02:10:25,625 because now we're going to start sending a lot of data back and forth 2626 02:10:25,625 --> 02:10:28,690 over the internet using Python and JavaScript. 2627 02:10:28,690 --> 02:10:32,590 Well let me go ahead now and open up this example as made in advance. 2628 02:10:32,590 --> 02:10:34,098 And this is in shows. 2629 02:10:34,098 --> 02:10:35,890 And we'll see a few files here, application 2630 02:10:35,890 --> 02:10:39,370 dot py, requirements dot text, and my templates, 2631 02:10:39,370 --> 02:10:42,250 which are index and layout and search. 2632 02:10:42,250 --> 02:10:46,250 All right, so a bunch but not more than we've really seen before. 2633 02:10:46,250 --> 02:10:48,460 And let's go ahead and, I kind of cheated earlier. 2634 02:10:48,460 --> 02:10:49,760 I didn't look at requirements. 2635 02:10:49,760 --> 02:10:51,820 But I might as well look at requirements for good measure. 2636 02:10:51,820 --> 02:10:54,737 Here's just an example of what else might be in requirements dot text: 2637 02:10:54,737 --> 02:10:56,230 CS50 library and Flask. 2638 02:10:56,230 --> 02:10:58,150 And again, those are preinstalled in the IDE, 2639 02:10:58,150 --> 02:11:00,358 but we do this so that if you get adventurous and try 2640 02:11:00,358 --> 02:11:03,850 running these things on your own Mac or PC, you have all of the configuration 2641 02:11:03,850 --> 02:11:04,760 that you need. 2642 02:11:04,760 --> 02:11:07,877 Well let's start as before with applications dot py, 2643 02:11:07,877 --> 02:11:09,460 and let me go ahead and do this first. 2644 02:11:09,460 --> 02:11:13,570 Let me run this thing first so we can actually see the app in motion 2645 02:11:13,570 --> 02:11:16,040 and then understand how it works. 2646 02:11:16,040 --> 02:11:19,600 So if I visit this, let me go ahead and type in office. 2647 02:11:19,600 --> 02:11:20,950 All right, nothing happens yet. 2648 02:11:20,950 --> 02:11:22,360 Let me click Search. 2649 02:11:22,360 --> 02:11:23,110 OK. 2650 02:11:23,110 --> 02:11:27,880 I then see a big bulleted list of all shows that mention office, so not 2651 02:11:27,880 --> 02:11:30,022 The Office per se, but an office. 2652 02:11:30,022 --> 02:11:32,480 And let me go ahead and zoom out here and look at the URLs. 2653 02:11:32,480 --> 02:11:33,730 Let me go back here. 2654 02:11:33,730 --> 02:11:35,688 Let me point out that we're at the slash route. 2655 02:11:35,688 --> 02:11:37,481 Again, the slash is there, it's just Chrome 2656 02:11:37,481 --> 02:11:39,160 is hiding it by default these days. 2657 02:11:39,160 --> 02:11:42,280 And when I search for something like office and hit Enter, 2658 02:11:42,280 --> 02:11:46,887 notice that I end up at slash search, question mark, q equals office. 2659 02:11:46,887 --> 02:11:48,970 So I borrowed some inspiration from Google, right? 2660 02:11:48,970 --> 02:11:51,070 I kind of cheated last week where I really only 2661 02:11:51,070 --> 02:11:53,740 implemented the front end to Google, the HTML form, 2662 02:11:53,740 --> 02:11:57,440 and then I let Google find me some cats and some dogs and so forth. 2663 02:11:57,440 --> 02:12:01,150 But now as, with Python, you now have the ability 2664 02:12:01,150 --> 02:12:04,220 to implement both sides of that application. 2665 02:12:04,220 --> 02:12:06,700 So if I look at the source code here, notice 2666 02:12:06,700 --> 02:12:10,990 that I seem to be returning a really big unordered list of list items that 2667 02:12:10,990 --> 02:12:14,460 represent, again, all the titles of office related shows. 2668 02:12:14,460 --> 02:12:16,210 All right, this is fine and good, but this 2669 02:12:16,210 --> 02:12:19,180 is of like old school web programming where you fill out 2670 02:12:19,180 --> 02:12:21,100 a form, you hit Enter, and boom. 2671 02:12:21,100 --> 02:12:23,890 But these days recall most any time you visit a website, 2672 02:12:23,890 --> 02:12:25,060 lots is happening at once. 2673 02:12:25,060 --> 02:12:26,860 You've got some autocomplete going on here, 2674 02:12:26,860 --> 02:12:29,300 you've got chat messages popping up here, 2675 02:12:29,300 --> 02:12:31,870 you've got a map over here that's automatically moving 2676 02:12:31,870 --> 02:12:34,700 and a little car for Uber is moving around at the same time. 2677 02:12:34,700 --> 02:12:37,520 Like the web of today, web 2.0 if you will, 2678 02:12:37,520 --> 02:12:40,810 which is not a technical term as much as it is a buzzword, 2679 02:12:40,810 --> 02:12:44,650 refers to just increasingly dynamic web interactions 2680 02:12:44,650 --> 02:12:46,330 between users and computers. 2681 02:12:46,330 --> 02:12:48,730 And with JavaScript and with your own backend, 2682 02:12:48,730 --> 02:12:50,560 be it Python or something else, you can now 2683 02:12:50,560 --> 02:12:53,320 begin to build these more dynamic interfaces as well. 2684 02:12:53,320 --> 02:12:58,330 Wouldn't it be cool if when I start typing O F F I C E, 2685 02:12:58,330 --> 02:13:00,530 we actually immediately saw the results. 2686 02:13:00,530 --> 02:13:01,777 And we've seen this already. 2687 02:13:01,777 --> 02:13:03,610 Last week, remember that I started searching 2688 02:13:03,610 --> 02:13:07,240 for all words that start with A, and I used a really large dictionary 2689 02:13:07,240 --> 02:13:11,500 from p set 5, but that was 140,000 words but just words. 2690 02:13:11,500 --> 02:13:15,340 This database of titles is several megabytes large. 2691 02:13:15,340 --> 02:13:18,190 And I don't necessarily want to send the entire database 2692 02:13:18,190 --> 02:13:21,698 of movies to the browser, one, because of performance and size, 2693 02:13:21,698 --> 02:13:23,240 and maybe two, intellectual property. 2694 02:13:23,240 --> 02:13:26,180 I don't really want to send every user my entire database. 2695 02:13:26,180 --> 02:13:29,380 You can imagine wanting to keep a little more control over the data you're 2696 02:13:29,380 --> 02:13:33,470 providing, requiring users to log in or pay for your service or the like. 2697 02:13:33,470 --> 02:13:36,820 So there's reasons where you might want the browser to talk to the server 2698 02:13:36,820 --> 02:13:40,850 and only get the data the user is searching for, not the whole thing. 2699 02:13:40,850 --> 02:13:41,840 So let's do that. 2700 02:13:41,840 --> 02:13:45,130 Let's enhance this show's application in such a way 2701 02:13:45,130 --> 02:13:47,170 that it actually does things more dynamically, 2702 02:13:47,170 --> 02:13:49,220 but let's first understand how it works. 2703 02:13:49,220 --> 02:13:52,990 So I have a couple of libraries here, CS50's and Flask. 2704 02:13:52,990 --> 02:13:54,760 I'm configuring Flask here. 2705 02:13:54,760 --> 02:13:57,580 I'm then configuring my database here. 2706 02:13:57,580 --> 02:13:59,950 Down here, I just have a very simple route 2707 02:13:59,950 --> 02:14:03,830 that renders index dot HTML, which apparently, let's take a look, 2708 02:14:03,830 --> 02:14:07,660 has that form, very simple, very similar to last week, 2709 02:14:07,660 --> 02:14:10,420 very similar to today, all of the forms we've done thus far. 2710 02:14:10,420 --> 02:14:14,470 Here's that name equals q, and everything else is pretty boilerplate. 2711 02:14:14,470 --> 02:14:15,970 So let's get rid of that file now. 2712 02:14:15,970 --> 02:14:19,340 The layout, also pretty boilerplate, it looks like things in the past. 2713 02:14:19,340 --> 02:14:23,350 So let's close that one as well and go back to index, application dot py. 2714 02:14:23,350 --> 02:14:25,540 So the juicy part seems to be the search route. 2715 02:14:25,540 --> 02:14:29,530 And this was the piece we were missing last week when we used Google instead 2716 02:14:29,530 --> 02:14:32,140 to find us some cats and some dogs. 2717 02:14:32,140 --> 02:14:35,020 Here I have a route called slash search, a function 2718 02:14:35,020 --> 02:14:37,220 called search that will be called for that route, 2719 02:14:37,220 --> 02:14:41,370 and here is kind of a nice amalgam of SQL and Python. 2720 02:14:41,370 --> 02:14:43,120 I'm going to give myself a variable called 2721 02:14:43,120 --> 02:14:45,580 shows, which is going to be the result of all of the rows 2722 02:14:45,580 --> 02:14:47,740 that come back when I execute this. 2723 02:14:47,740 --> 02:14:54,020 Select star from shows where title is like this placeholder question mark. 2724 02:14:54,020 --> 02:14:55,470 Now what am I going to plug-in? 2725 02:14:55,470 --> 02:14:58,110 Notice it's a little cryptic at first glance, 2726 02:14:58,110 --> 02:15:02,430 but I seem to be taking the user's input, q, from request 2727 02:15:02,430 --> 02:15:06,510 dot args dot get, so that's using get apparently because of the word args, 2728 02:15:06,510 --> 02:15:08,940 and it's not form now, it's request dot args. 2729 02:15:08,940 --> 02:15:12,900 So I'm getting the user's q value, which was office in my case, and just 2730 02:15:12,900 --> 02:15:14,810 as a quick check, what's with the percent 2731 02:15:14,810 --> 02:15:17,250 signs on the left and the right? 2732 02:15:17,250 --> 02:15:21,590 Because we've seen a lot of percent signs today, but these are different. 2733 02:15:21,590 --> 02:15:22,520 Perhaps in the chat? 2734 02:15:22,520 --> 02:15:26,170 What do these percent signs represent in this context? 2735 02:15:26,170 --> 02:15:28,160 Brian, you want to echo the consensus? 2736 02:15:28,160 --> 02:15:30,580 BRIAN: Yeah, people are saying they're SQL placeholders. 2737 02:15:30,580 --> 02:15:33,137 DAVID J. MALAN: Yeah, so SQL wildcard placeholders. 2738 02:15:33,137 --> 02:15:36,220 That means zero or more characters to the left, zero or more to the right. 2739 02:15:36,220 --> 02:15:40,870 This is why I was getting matches with office at the beginning of the word, 2740 02:15:40,870 --> 02:15:42,920 office at the end, and office in the middle. 2741 02:15:42,920 --> 02:15:45,670 If I really wanted to be anal I could get rid of the percent signs 2742 02:15:45,670 --> 02:15:48,400 and require only a perfect match, but that's not my goal 2743 02:15:48,400 --> 02:15:50,570 with this particular implementation. 2744 02:15:50,570 --> 02:15:54,430 Once I get back all of, whoops, once I get back all of these rows 2745 02:15:54,430 --> 02:15:58,870 I have here a line, return render template, search dot HTML, 2746 02:15:58,870 --> 02:16:00,230 passing in all of those shows. 2747 02:16:00,230 --> 02:16:02,620 So the last thing to look at is search dot HTML. 2748 02:16:02,620 --> 02:16:04,768 It's pretty simple, and surely like an hour ago 2749 02:16:04,768 --> 02:16:06,310 this would have looked super cryptic. 2750 02:16:06,310 --> 02:16:08,650 It frankly might very well still look cryptic. 2751 02:16:08,650 --> 02:16:10,720 But once you start using this syntax yourself 2752 02:16:10,720 --> 02:16:13,540 you'll see that, oh, this is just a template that 2753 02:16:13,540 --> 02:16:19,930 is allowing me to dynamically output an unordered list of LI tags, each 2754 02:16:19,930 --> 02:16:26,770 of which represents the title of a show that's been passed into this template. 2755 02:16:26,770 --> 02:16:27,580 All right. 2756 02:16:27,580 --> 02:16:29,740 So now then the final flourish. 2757 02:16:29,740 --> 02:16:34,299 Let's go about enhancing this application so that there is no form 2758 02:16:34,299 --> 02:16:37,540 to submit in the same way, but instead all of the logic 2759 02:16:37,540 --> 02:16:41,813 actually happens between JavaScript and the backend. 2760 02:16:41,813 --> 02:16:43,480 I'm going to go ahead and do this first. 2761 02:16:43,480 --> 02:16:47,582 I'm going to go back to application dot py here, and instead of this here, 2762 02:16:47,582 --> 02:16:50,290 I'm going to go ahead and do the following: I'm going to go ahead 2763 02:16:50,290 --> 02:16:53,230 and instead of rendering a template, I'm going 2764 02:16:53,230 --> 02:16:55,870 to use a new function called jsonify. 2765 02:16:55,870 --> 02:16:59,090 It's kind of a funny name, and I have to import it up here. 2766 02:16:59,090 --> 02:17:01,270 So let me import jsonify. 2767 02:17:01,270 --> 02:17:06,785 It turns out that jsonify, or json, means JavaScript Object Notation. 2768 02:17:06,785 --> 02:17:08,660 And we'll see what it looks like in a moment. 2769 02:17:08,660 --> 02:17:11,110 But the world years ago standardized on a format 2770 02:17:11,110 --> 02:17:14,379 for transmitting data between servers and browsers 2771 02:17:14,379 --> 02:17:19,510 using a very lightweight text format, Jason, or json, JavaScript Object 2772 02:17:19,510 --> 02:17:20,709 Notation. 2773 02:17:20,709 --> 02:17:26,709 Jsonify is a Flask function that takes a Python list or a Python dictionary 2774 02:17:26,709 --> 02:17:29,080 and converts it into json format. 2775 02:17:29,080 --> 02:17:30,980 So we'll see this in just a moment. 2776 02:17:30,980 --> 02:17:35,980 So notice that I'm now returning the jsonification of the show's 2777 02:17:35,980 --> 02:17:41,270 variable, which recall is just the rows that came back from db dot execute. 2778 02:17:41,270 --> 02:17:42,830 So let's see this in action. 2779 02:17:42,830 --> 02:17:44,830 I'm actually going to go to my, let me go ahead 2780 02:17:44,830 --> 02:17:47,889 and restart the server because I've made some changes. 2781 02:17:47,889 --> 02:17:52,450 Let me go ahead and now go to the server slash search, question mark, 2782 02:17:52,450 --> 02:17:53,740 q equals office. 2783 02:17:53,740 --> 02:17:56,709 So I'm going to manually visit this URL and hit Enter. 2784 02:17:56,709 --> 02:17:58,330 Notice what comes back. 2785 02:17:58,330 --> 02:18:00,980 It's kind of cryptic at first glance here. 2786 02:18:00,980 --> 02:18:04,900 But notice this is indeed what's called JavaScript Object Notation. 2787 02:18:04,900 --> 02:18:07,650 There's a square bracket over here at top left. 2788 02:18:07,650 --> 02:18:10,780 This means, hey browser, here comes a list. 2789 02:18:10,780 --> 02:18:12,940 There's a curly brace, which means, hey browser 2790 02:18:12,940 --> 02:18:16,900 here comes a dictionary, otherwise known as an object in JavaScript. 2791 02:18:16,900 --> 02:18:20,860 Quote unquote ID is the key in this dictionary. 2792 02:18:20,860 --> 02:18:24,730 108878 is the value of that key. 2793 02:18:24,730 --> 02:18:27,850 Here comes the second key, quote unquote title, the value of which 2794 02:18:27,850 --> 02:18:30,100 is nice day at the office, quote unquote. 2795 02:18:30,100 --> 02:18:31,959 Then there's a closed curly brace, which is 2796 02:18:31,959 --> 02:18:35,410 end of the dictionary or end of the object, a comma, 2797 02:18:35,410 --> 02:18:38,629 and then there's a whole bunch of these other dictionaries. 2798 02:18:38,629 --> 02:18:42,670 So in short, all we're looking at here is a very raw text 2799 02:18:42,670 --> 02:18:46,090 based format of a Python dictionary converted to again, 2800 02:18:46,090 --> 02:18:48,760 something called json, JavaScript Object Notation, 2801 02:18:48,760 --> 02:18:50,410 which literally, this is about it. 2802 02:18:50,410 --> 02:18:55,690 Json uses double quotes, colons, curly braces, and square brackets, 2803 02:18:55,690 --> 02:18:59,120 and that's about it, to represent information. 2804 02:18:59,120 --> 02:19:00,400 So this is great. 2805 02:19:00,400 --> 02:19:03,790 But this is a horrible, horrible user interface if what the user sees 2806 02:19:03,790 --> 02:19:04,870 is this mess. 2807 02:19:04,870 --> 02:19:06,230 But that's not the point. 2808 02:19:06,230 --> 02:19:11,709 The point now is to have our backend return a json array of search results 2809 02:19:11,709 --> 02:19:15,167 and let the browser convert it into HTML. 2810 02:19:15,167 --> 02:19:17,500 Recall from last week I claimed that with JavaScript you 2811 02:19:17,500 --> 02:19:20,620 can mutate or change your dom, the document 2812 02:19:20,620 --> 02:19:22,750 object model, the tree in memory. 2813 02:19:22,750 --> 02:19:25,059 And what you can do in particular with JavaScript 2814 02:19:25,059 --> 02:19:27,760 is add more nodes to that tree. 2815 02:19:27,760 --> 02:19:31,150 You can add more things to that family tree like structure. 2816 02:19:31,150 --> 02:19:32,260 So yes, hello. 2817 02:19:32,260 --> 02:19:34,937 We just got, Hi, David, Hi, David, Hi, David via get. 2818 02:19:34,937 --> 02:19:35,770 Thank you very much. 2819 02:19:35,770 --> 02:19:36,430 OK. 2820 02:19:36,430 --> 02:19:41,170 So let me minimize that, and let me open up now, not 2821 02:19:41,170 --> 02:19:44,150 search dot HTML which we're not going to bother using anymore, 2822 02:19:44,150 --> 02:19:46,777 but instead index dot HTML. 2823 02:19:46,777 --> 02:19:48,610 And index dot HTML, you know what, I'm going 2824 02:19:48,610 --> 02:19:50,530 to go ahead and borrow some code here. 2825 02:19:50,530 --> 02:19:52,868 I'm going to go ahead and open up index dot HTML, 2826 02:19:52,868 --> 02:19:54,160 and I'm going to simplify this. 2827 02:19:54,160 --> 02:19:55,450 Let me stop the server. 2828 02:19:55,450 --> 02:19:58,630 I'm going to go ahead and get rid of my layout template, 2829 02:19:58,630 --> 02:20:00,670 and I'm going to get rid of my search template 2830 02:20:00,670 --> 02:20:02,630 because I just don't need them anymore. 2831 02:20:02,630 --> 02:20:10,570 So I'm going to simplify this program and focus entirely now on index dot 2832 02:20:10,570 --> 02:20:11,200 HTML. 2833 02:20:11,200 --> 02:20:12,850 So what do I want to do in here? 2834 02:20:12,850 --> 02:20:15,340 I need to involve some JavaScript now. 2835 02:20:15,340 --> 02:20:17,660 So how am I going to go about doing this? 2836 02:20:17,660 --> 02:20:22,000 Well first I need to go ahead and use a library called jQuery, 2837 02:20:22,000 --> 02:20:27,553 and jQuery is something that's a little decreasing in popularity, 2838 02:20:27,553 --> 02:20:29,470 but it's still used by Bootstrap, and so we'll 2839 02:20:29,470 --> 02:20:32,600 continue using it because you're already including it in fact, 2840 02:20:32,600 --> 02:20:35,900 for some of your other examples, but we need a different version of it. 2841 02:20:35,900 --> 02:20:39,940 So I'm going to quickly Google jQuery CDN, I'm going to go to this website, 2842 02:20:39,940 --> 02:20:42,040 and long story short, there's a lot of libraries 2843 02:20:42,040 --> 02:20:45,730 out there that you can use by just grabbing their script tag 2844 02:20:45,730 --> 02:20:47,495 and using it inside of your own. 2845 02:20:47,495 --> 02:20:50,120 So I'm going to go ahead here, and let me just clean up the tag 2846 02:20:50,120 --> 02:20:53,898 so it's all in one long, if ugly, line, but via copying and pasting 2847 02:20:53,898 --> 02:20:57,190 that line, which we'll typically do for you in the problem sets in distribution 2848 02:20:57,190 --> 02:21:00,410 code, I'm going to go ahead and copy that library into my file 2849 02:21:00,410 --> 02:21:02,860 so that it's among the libraries I can use. 2850 02:21:02,860 --> 02:21:05,380 And now I'm going to go ahead, just as we did last week, 2851 02:21:05,380 --> 02:21:09,100 and I'm going to add a script tag inside of my own pages head, 2852 02:21:09,100 --> 02:21:12,630 and then down here, let's see, where do I want to do this? 2853 02:21:12,630 --> 02:21:13,630 Actually, you know what? 2854 02:21:13,630 --> 02:21:16,990 Let me go ahead and do this a little differently just for consistency 2855 02:21:16,990 --> 02:21:18,260 with what you'll see online. 2856 02:21:18,260 --> 02:21:20,260 I'm going to go ahead and do this all in my body 2857 02:21:20,260 --> 02:21:24,460 so we don't have to worry about things being out of order. 2858 02:21:24,460 --> 02:21:26,805 We'll indeed keep it all inside of the page's body. 2859 02:21:26,805 --> 02:21:28,680 And what I'm going to do is give myself this: 2860 02:21:28,680 --> 02:21:32,550 an input, autocomplete equals quote unquote off, 2861 02:21:32,550 --> 02:21:38,130 autofocus, and then I'm going to give it a placeholder of query 2862 02:21:38,130 --> 02:21:39,935 and then a type of text. 2863 02:21:39,935 --> 02:21:42,060 So I'm going to have a very simple search box there 2864 02:21:42,060 --> 02:21:44,970 and I'm going to have an unordered list with nothing in it. 2865 02:21:44,970 --> 02:21:46,710 And that's deliberate for now. 2866 02:21:46,710 --> 02:21:50,820 Then I'm going to import this, the jQuery library. 2867 02:21:50,820 --> 02:21:53,460 And then down here, inside of my own script tags, 2868 02:21:53,460 --> 02:21:56,850 this is where I'm going to write the actual code. 2869 02:21:56,850 --> 02:22:00,100 I'm going to do let input equals document dot, 2870 02:22:00,100 --> 02:22:03,480 let's do query selector just like last week, and let me go ahead 2871 02:22:03,480 --> 02:22:05,320 and select my input tag. 2872 02:22:05,320 --> 02:22:06,070 This works. 2873 02:22:06,070 --> 02:22:09,240 I don't need an ID or any class because at the moment I only have one input, 2874 02:22:09,240 --> 02:22:14,010 so query selector of quote unquote input will give me that tag specifically. 2875 02:22:14,010 --> 02:22:16,710 Let me go ahead now and add to that input 2876 02:22:16,710 --> 02:22:20,880 an event listener that listens for the key up event. 2877 02:22:20,880 --> 02:22:23,730 Recall from last week our discussion of events, and key up, 2878 02:22:23,730 --> 02:22:25,920 like the user touching and letting go of the key 2879 02:22:25,920 --> 02:22:27,630 is one of the events you can listen for. 2880 02:22:27,630 --> 02:22:31,140 And any time the user does that, I want to call the following function, 2881 02:22:31,140 --> 02:22:33,750 and it's an anonymous function which we saw last week too. 2882 02:22:33,750 --> 02:22:37,660 And what I'm going to do inside of this anonymous function is the following. 2883 02:22:37,660 --> 02:22:41,310 I'm going to call a new function, the only new JavaScript function today, 2884 02:22:41,310 --> 02:22:43,500 called dollar sign underscore get. 2885 02:22:43,500 --> 02:22:46,980 This is shorthand notation for jQuery dot get, 2886 02:22:46,980 --> 02:22:52,390 but, sorry, dollar sign dot get is shorthand for jQuery dot get. 2887 02:22:52,390 --> 02:22:54,390 And I'm going to go ahead and get the following. 2888 02:22:54,390 --> 02:23:00,240 I'm going to get a slash search URL with a question mark followed by q equals, 2889 02:23:00,240 --> 02:23:04,960 and then I'm going to go ahead and put input dot value. 2890 02:23:04,960 --> 02:23:08,130 So notice with this line of code, this JavaScript string, 2891 02:23:08,130 --> 02:23:11,940 I'm kind of dynamically constructing in JavaScript code 2892 02:23:11,940 --> 02:23:17,495 the URL that I want to request shows from, slash search question 2893 02:23:17,495 --> 02:23:20,760 mark q equals, whatever the value of the input box 2894 02:23:20,760 --> 02:23:23,580 was that the user typed something into. 2895 02:23:23,580 --> 02:23:26,970 And the way this dollar sign dot get function works 2896 02:23:26,970 --> 02:23:28,890 is it supports what's called a callback. 2897 02:23:28,890 --> 02:23:31,260 A callback is a function that will eventually be 2898 02:23:31,260 --> 02:23:33,635 called when it has an answer for you. 2899 02:23:33,635 --> 02:23:35,010 And this is important on the web. 2900 02:23:35,010 --> 02:23:37,290 The internet can sometimes be slow, and you 2901 02:23:37,290 --> 02:23:39,510 might want to write code that contacts another server 2902 02:23:39,510 --> 02:23:40,602 like I'm about to do now. 2903 02:23:40,602 --> 02:23:43,560 And that server might be slow or the internet connection might be slow, 2904 02:23:43,560 --> 02:23:46,350 and it would be annoying if your entire browser froze 2905 02:23:46,350 --> 02:23:50,490 while you waited and waited and waited for the server's response to come back. 2906 02:23:50,490 --> 02:23:54,180 It's a lot nicer if you can say, when you have the data, 2907 02:23:54,180 --> 02:23:57,900 call me back, so to speak, sort of metaphorically on the phone, 2908 02:23:57,900 --> 02:24:00,130 call me back by calling this function. 2909 02:24:00,130 --> 02:24:02,110 So what function do I want it to call? 2910 02:24:02,110 --> 02:24:04,470 I want it to call this anonymous function that's 2911 02:24:04,470 --> 02:24:07,830 going to take as input an argument called shows, 2912 02:24:07,830 --> 02:24:11,410 but I could call that anything I want, and I'm going to do this. 2913 02:24:11,410 --> 02:24:13,680 I'm going to create an HTML string that's 2914 02:24:13,680 --> 02:24:15,900 initially nothing, quote unquote. 2915 02:24:15,900 --> 02:24:18,420 I'm then going to do this, a for loop in JavaScript 2916 02:24:18,420 --> 02:24:24,840 letting a variable called ID equal to whatever ID is in the shows that just 2917 02:24:24,840 --> 02:24:28,830 came back to me, and now inside of this for loop, 2918 02:24:28,830 --> 02:24:31,860 let me go ahead and inside of this for loop 2919 02:24:31,860 --> 02:24:35,710 create a title that's equal to shows, which is again, 2920 02:24:35,710 --> 02:24:40,140 the data that came back on the, came back via that callback so 2921 02:24:40,140 --> 02:24:46,450 to speak, shows dot ID dot title, and semicolon, 2922 02:24:46,450 --> 02:24:54,190 then I'm going to do HTML plus equals quote unquote list item plus title 2923 02:24:54,190 --> 02:24:57,550 plus quote unquote closed list item. 2924 02:24:57,550 --> 02:25:03,400 Then down here, lastly, I'm going to do document dot query selector, quote 2925 02:25:03,400 --> 02:25:07,580 unquote ul, dot inner HTML gets HTML. 2926 02:25:07,580 --> 02:25:09,580 All right, this is definitely the craziest thing 2927 02:25:09,580 --> 02:25:11,410 we've done thus far today, and it's tying together 2928 02:25:11,410 --> 02:25:14,710 so many different ideas, not to mention new syntax, so of all the examples, 2929 02:25:14,710 --> 02:25:17,710 don't worry too much if this is just a lot at once. 2930 02:25:17,710 --> 02:25:19,630 The goal really now is not to introduce you 2931 02:25:19,630 --> 02:25:22,330 to this syntax so that you can repeat it tomorrow, but rather 2932 02:25:22,330 --> 02:25:24,020 the idea of what we're doing. 2933 02:25:24,020 --> 02:25:25,220 So what are we doing? 2934 02:25:25,220 --> 02:25:27,640 We have a simple web page with a text input. 2935 02:25:27,640 --> 02:25:31,600 We've got a simple web page with an unordered list that's currently empty. 2936 02:25:31,600 --> 02:25:35,380 Below that, we're including this third party JavaScript library called jQuery, 2937 02:25:35,380 --> 02:25:39,340 which Bootstrap also happens to use for some of its graphical components. 2938 02:25:39,340 --> 02:25:41,920 Then I have my own JavaScript code that first 2939 02:25:41,920 --> 02:25:46,480 declares a variable that gives me access to the input tag on my own webpage 2940 02:25:46,480 --> 02:25:47,800 a few lines above. 2941 02:25:47,800 --> 02:25:49,990 I'm then using this fancy function dollar sign 2942 02:25:49,990 --> 02:25:52,660 get to do what's called an AJAX call. 2943 02:25:52,660 --> 02:25:55,960 AJAX refers to the ability for a web page 2944 02:25:55,960 --> 02:26:01,180 to make additional HTTP requests programmatically to a server. 2945 02:26:01,180 --> 02:26:03,970 It is allowing, this is how all websites today 2946 02:26:03,970 --> 02:26:07,360 get your chat messages if a friend just messaged you on some platform. 2947 02:26:07,360 --> 02:26:10,250 It's how when you're typing in your address, 2948 02:26:10,250 --> 02:26:13,060 it can autocomplete your address based on the entire globe's 2949 02:26:13,060 --> 02:26:14,020 worth of addresses. 2950 02:26:14,020 --> 02:26:16,570 It's how Google search autocomplete works as well. 2951 02:26:16,570 --> 02:26:20,025 Dollar sign dot get is a function built into jQuery that's 2952 02:26:20,025 --> 02:26:22,150 using some standard JavaScript functionality that's 2953 02:26:22,150 --> 02:26:25,420 going to allow me to visit the URL that ends with slash search 2954 02:26:25,420 --> 02:26:28,630 question mark q equals whatever the human typed in, 2955 02:26:28,630 --> 02:26:32,050 and when the response is ready, this anonymous function 2956 02:26:32,050 --> 02:26:34,870 is going to get called back, and it's going to be handed an input, 2957 02:26:34,870 --> 02:26:39,580 an argument called shows that is going to equal this stuff. 2958 02:26:39,580 --> 02:26:44,980 This is what my JavaScript function is going to receive as its shows argument. 2959 02:26:44,980 --> 02:26:48,370 And notice, it's a list or an array, inside 2960 02:26:48,370 --> 02:26:53,620 of which is a list of dictionaries or objects with two keys, ID, and title. 2961 02:26:53,620 --> 02:26:56,440 This, let me stipulate, happens to be the syntax in JavaScript 2962 02:26:56,440 --> 02:26:58,720 for iterating over such a data structure, 2963 02:26:58,720 --> 02:27:01,360 and this happens to be the syntax in JavaScript 2964 02:27:01,360 --> 02:27:06,070 for allowing me to create one line after another, another LI, another LI, 2965 02:27:06,070 --> 02:27:10,780 appending it using concatenation to this variable called HTML. 2966 02:27:10,780 --> 02:27:13,360 And this very last line of code says to the browser, 2967 02:27:13,360 --> 02:27:17,890 go select me that UL and plug into its inner HTML 2968 02:27:17,890 --> 02:27:20,980 the contents of it, the value of my variable. 2969 02:27:20,980 --> 02:27:25,120 And now crossing my fingers I did not screw up syntactically, let me go ahead 2970 02:27:25,120 --> 02:27:29,140 and do Flask run, I still need to run Flask because I do have a backend here. 2971 02:27:29,140 --> 02:27:33,550 Let me go back to my browser and reload the slash route. 2972 02:27:33,550 --> 02:27:38,080 Let me go ahead now and type in O, F, dammit. 2973 02:27:38,080 --> 02:27:39,460 Oh wait, it was just slow. 2974 02:27:39,460 --> 02:27:42,850 So notice, everything I've typed thus far or everything I'm seeing thus far 2975 02:27:42,850 --> 02:27:44,330 matches the word off. 2976 02:27:44,330 --> 02:27:47,140 And if I continue this, office, and let it search 2977 02:27:47,140 --> 02:27:49,250 and let the internet do its thing, now indeed, 2978 02:27:49,250 --> 02:27:51,520 it's been whittled down to a list of office matches. 2979 02:27:51,520 --> 02:27:53,560 And notice again if I go to the inspect tab, 2980 02:27:53,560 --> 02:27:58,330 open the network tab under inspect, let me go ahead and type in office, 2981 02:27:58,330 --> 02:28:05,440 notice here that every keystroke I typed triggered, O F F I C E to be executed, 2982 02:28:05,440 --> 02:28:08,770 triggered an AJAX call, that is an HTTP call to the server. 2983 02:28:08,770 --> 02:28:12,290 And notice that if I click on the last one there, scroll down, 2984 02:28:12,290 --> 02:28:14,980 I will see not only my request and my response, 2985 02:28:14,980 --> 02:28:18,700 but if I click on the response, I'll indeed see this big json 2986 02:28:18,700 --> 02:28:20,212 array of all of the data. 2987 02:28:20,212 --> 02:28:22,420 And it's actually rather fortuitous that it was slow, 2988 02:28:22,420 --> 02:28:24,212 because we were going to end with one demo. 2989 02:28:24,212 --> 02:28:26,740 For instance, if I was curious to know, being indoors 2990 02:28:26,740 --> 02:28:28,870 all day, what the weather is like, I might maybe 2991 02:28:28,870 --> 02:28:33,074 call Brian up on this here telephone. 2992 02:28:33,074 --> 02:28:38,530 [PHONE RINGING] 2993 02:28:38,530 --> 02:28:39,430 BRIAN: Hello? 2994 02:28:39,430 --> 02:28:42,910 DAVID J. MALAN: Hi, Brian, do you know what the weather is like outside today? 2995 02:28:42,910 --> 02:28:44,740 BRIAN: I haven't been outside in a little bit, but I can check, 2996 02:28:44,740 --> 02:28:45,970 and I will call you back. 2997 02:28:45,970 --> 02:28:46,360 DAVID J. MALAN: OK. 2998 02:28:46,360 --> 02:28:48,520 And notice it would be annoying if I had to wait on the phone for him 2999 02:28:48,520 --> 02:28:49,103 to go outside. 3000 02:28:49,103 --> 02:28:52,622 So I'm going to hang up, and I'm just going to wait for him to call me back, 3001 02:28:52,622 --> 02:28:54,580 and that's exactly what's happening in my code. 3002 02:28:54,580 --> 02:28:58,690 When I pass this anonymous function to this get function, 3003 02:28:58,690 --> 02:29:01,930 and they get here means HTTP get, this is telling the browser, 3004 02:29:01,930 --> 02:29:04,840 call this function once you have the answer, 3005 02:29:04,840 --> 02:29:11,520 much like hopefully Brian's about to have the, and indeed, the call back. 3006 02:29:11,520 --> 02:29:12,160 Hello. 3007 02:29:12,160 --> 02:29:13,330 BRIAN: Hi. 3008 02:29:13,330 --> 02:29:14,350 I looked up the weather. 3009 02:29:14,350 --> 02:29:16,600 It looks like it's going to be a brisk fall day today. 3010 02:29:16,600 --> 02:29:18,683 DAVID J. MALAN: Wonderful, well thank you so much. 3011 02:29:18,683 --> 02:29:20,110 And that is it for CS50. 3012 02:29:20,110 --> 02:29:22,720 We will see you all next time. 3013 02:29:22,720 --> 02:29:26,070 [MUSIC PLAYING] 3014 02:29:26,070 --> 02:30:23,000