1 00:00:00,000 --> 00:00:00,500 2 00:00:00,500 --> 00:00:03,992 [MUSIC PLAYING] 3 00:00:03,992 --> 00:00:49,910 4 00:00:49,910 --> 00:00:51,190 DAVID MALAN: All right. 5 00:00:51,190 --> 00:00:55,060 This CS50 and this is lecture 7 wherein we pick up 6 00:00:55,060 --> 00:00:58,060 where we left off last time in talking more about Python, 7 00:00:58,060 --> 00:01:02,340 but this time using Python for even more powerful purposes, 8 00:01:02,340 --> 00:01:04,980 an alliteration I didn't intend until I just said it there. 9 00:01:04,980 --> 00:01:07,660 But the goal here with Python now is to actually use 10 00:01:07,660 --> 00:01:11,530 this language to generate another language, in particular HTML. 11 00:01:11,530 --> 00:01:15,010 And what we'll do is start to provide all the more of a mental model 12 00:01:15,010 --> 00:01:17,500 for what you would call separation of concerns, whereby 13 00:01:17,500 --> 00:01:21,190 when you design more complicated web based, or rather when you design 14 00:01:21,190 --> 00:01:25,681 more complicated software, you tend to try to adopt certain design patterns so 15 00:01:25,681 --> 00:01:28,180 that you're not just writing everything in one big file that 16 00:01:28,180 --> 00:01:31,990 gets a little confusing, unwieldy to maintain and to add to over time. 17 00:01:31,990 --> 00:01:34,930 But you start to separate your concerns, and your functionality, 18 00:01:34,930 --> 00:01:36,970 and your features, and your collaborators' work 19 00:01:36,970 --> 00:01:39,089 into different files and different methodologies. 20 00:01:39,089 --> 00:01:42,130 So we'll try to give you some of these industry standard approaches today 21 00:01:42,130 --> 00:01:43,840 and why they actually solved problems. 22 00:01:43,840 --> 00:01:45,340 But, of course, how did we get here? 23 00:01:45,340 --> 00:01:46,920 A few weeks ago, we talked about this thing, 24 00:01:46,920 --> 00:01:48,910 this virtual envelope that just represents 25 00:01:48,910 --> 00:01:52,600 packets of information, zeros and ones, going across the internet from point A 26 00:01:52,600 --> 00:01:55,120 to point B. And among the messages in these envelopes 27 00:01:55,120 --> 00:01:56,440 might be for web requests. 28 00:01:56,440 --> 00:02:00,910 And we talked about HTTP, a protocol, hypertext transfer protocol, 29 00:02:00,910 --> 00:02:03,910 that just sends message like this inside of the envelope. 30 00:02:03,910 --> 00:02:06,100 And this is requesting, of course, the default page 31 00:02:06,100 --> 00:02:08,110 of a website as implied by the slash. 32 00:02:08,110 --> 00:02:11,030 And in many cases, but not always, this implies 33 00:02:11,030 --> 00:02:13,270 a default file name of index.html. 34 00:02:13,270 --> 00:02:16,540 But that's a human convention, not a requirement. 35 00:02:16,540 --> 00:02:20,840 Hopefully, the server responds with a numeric code equal to what integer? 36 00:02:20,840 --> 00:02:23,480 37 00:02:23,480 --> 00:02:26,220 200, hopefully, a number that we never actually 38 00:02:26,220 --> 00:02:28,140 really see unless you get more comfortable 39 00:02:28,140 --> 00:02:30,439 and start poking around Chrome's inspector 40 00:02:30,439 --> 00:02:31,980 and you look at your network traffic. 41 00:02:31,980 --> 00:02:32,479 Right. 42 00:02:32,479 --> 00:02:34,780 So here is an actual successful response, 43 00:02:34,780 --> 00:02:36,720 which means everything is indeed OK. 44 00:02:36,720 --> 00:02:40,070 And if the browser looks a little farther down in the virtual envelope, 45 00:02:40,070 --> 00:02:43,950 if you will, it will see another language called HTML, HyperText Markup 46 00:02:43,950 --> 00:02:46,660 Language, which is the stuff we wrote a couple of weeks ago 47 00:02:46,660 --> 00:02:51,240 and you'll continue writing this week as you now dynamically generate websites. 48 00:02:51,240 --> 00:02:55,200 But what we'll introduce today is what's also known as a framework, 49 00:02:55,200 --> 00:02:58,920 or, more precisely, a microframework, because we'll see in just a few minutes 50 00:02:58,920 --> 00:03:02,090 time that it can actually be really annoying and really tedious 51 00:03:02,090 --> 00:03:05,490 to generate websites automatically using Python 52 00:03:05,490 --> 00:03:07,890 if you have to write Python code alone. 53 00:03:07,890 --> 00:03:09,750 And so humans, over the past several years, 54 00:03:09,750 --> 00:03:13,470 have noticed, wow, every time I make a web application using Python, 55 00:03:13,470 --> 00:03:15,690 I find myself typing the same lines of code 56 00:03:15,690 --> 00:03:18,985 again and again just to get started, or when I'm collaborating with someone 57 00:03:18,985 --> 00:03:21,360 else, I find that, ooh, it's a little hard to collaborate 58 00:03:21,360 --> 00:03:23,370 if we're all working in the same file. 59 00:03:23,370 --> 00:03:25,650 So humans have invented what are called frameworks. 60 00:03:25,650 --> 00:03:29,040 And this is an example of code written in Python 61 00:03:29,040 --> 00:03:31,530 but using a framework called Flask. 62 00:03:31,530 --> 00:03:34,740 So whereas Bootstrap, which you've played with a little bit, 63 00:03:34,740 --> 00:03:38,640 is a framework for CSS and JavaScript, they have some dynamic features 64 00:03:38,640 --> 00:03:42,000 as well, Flask is a framework for Python that 65 00:03:42,000 --> 00:03:45,480 just gives you some library code that you can use freely 66 00:03:45,480 --> 00:03:46,950 in your own applications. 67 00:03:46,950 --> 00:03:50,490 And it just makes it, ultimately, a little easier to get your work done 68 00:03:50,490 --> 00:03:52,620 and build the thing you want to build as opposed 69 00:03:52,620 --> 00:03:57,540 to having to reinvent the wheel again and again like people before you. 70 00:03:57,540 --> 00:04:01,680 And so here is a methodology to which I alluded earlier just to have 71 00:04:01,680 --> 00:04:03,480 a mental model for the coming weeks. 72 00:04:03,480 --> 00:04:05,850 So up until now, pretty much every program 73 00:04:05,850 --> 00:04:09,660 we've written in C and most recently in Python 74 00:04:09,660 --> 00:04:14,110 you could call like controller code or controller logic or business logic. 75 00:04:14,110 --> 00:04:14,610 Right. 76 00:04:14,610 --> 00:04:16,980 It's all about getting something done logically, 77 00:04:16,980 --> 00:04:21,360 usually in one file, maybe two files if you have another helpers.ce or header 78 00:04:21,360 --> 00:04:22,710 file or whatnot. 79 00:04:22,710 --> 00:04:24,120 But we've been writing logic. 80 00:04:24,120 --> 00:04:26,940 But today and two weeks ago when we will focus 81 00:04:26,940 --> 00:04:31,060 on web programming in HTML and CSS, there's the second part of our world. 82 00:04:31,060 --> 00:04:34,380 There's like the logic that gets the interesting work done with loops, 83 00:04:34,380 --> 00:04:35,850 and conditions, and all that. 84 00:04:35,850 --> 00:04:37,980 But there's also now going to be the aesthetics, 85 00:04:37,980 --> 00:04:42,390 the stuff that the user actually sees and the way you present your data. 86 00:04:42,390 --> 00:04:45,300 So we're going to just introduce two letters of an acronym 87 00:04:45,300 --> 00:04:46,670 today moving forward. 88 00:04:46,670 --> 00:04:49,590 Anytime you start writing logical code in Python, 89 00:04:49,590 --> 00:04:51,480 it's going to be called your controller. 90 00:04:51,480 --> 00:04:55,200 It's sort of like the machine that operates your entire web application, 91 00:04:55,200 --> 00:04:57,180 but anytime you do something more aesthetic, 92 00:04:57,180 --> 00:05:01,470 we're going to call that your view code, so C and V being the letters here. 93 00:05:01,470 --> 00:05:03,900 And this just refers to a separation of concerns. 94 00:05:03,900 --> 00:05:05,340 Your logic goes in this file. 95 00:05:05,340 --> 00:05:08,160 And your aesthetics and formatting go in this other file. 96 00:05:08,160 --> 00:05:12,090 Next week, we'll introduce databases in SQL, structured query language. 97 00:05:12,090 --> 00:05:15,230 And we'll introduce an M here, because the acronym that's 98 00:05:15,230 --> 00:05:18,060 in vogue for quite some time now is MVC, though there 99 00:05:18,060 --> 00:05:19,770 are alternatives to this mental model. 100 00:05:19,770 --> 00:05:21,600 And that just means there are three different types 101 00:05:21,600 --> 00:05:24,433 of things you should be thinking about when building an application. 102 00:05:24,433 --> 00:05:27,180 But today we're going to focus on these two, controller and view. 103 00:05:27,180 --> 00:05:30,840 And up until now, we've pretty much been doing entirely controller stuff 104 00:05:30,840 --> 00:05:32,130 when writing code. 105 00:05:32,130 --> 00:05:35,940 So the motivation, ultimately, will be to get to the point of building, 106 00:05:35,940 --> 00:05:39,540 essentially, this, the freshman intramural sports website, 107 00:05:39,540 --> 00:05:44,400 which I was the first one to make back in 1996 as a sophomore, 108 00:05:44,400 --> 00:05:48,120 maybe 1997 as a junior, after having only taken CS50 and a follow 109 00:05:48,120 --> 00:05:49,590 on class CS51. 110 00:05:49,590 --> 00:05:54,120 And even though this is horrifying to see nowadays, underneath the hood 111 00:05:54,120 --> 00:05:57,650 was a whole bunch of controller logic and a whole bunch of model code, 112 00:05:57,650 --> 00:06:00,060 even though I don't think MVC existed as an acronym 113 00:06:00,060 --> 00:06:02,680 back then till humans figured out the pattern. 114 00:06:02,680 --> 00:06:06,400 But what it did have via the menu up here was a whole lot of functionality. 115 00:06:06,400 --> 00:06:09,390 So no longer did you have to walk across campus filling out a form 116 00:06:09,390 --> 00:06:13,080 and drop off a sheet of paper in an RA or a proctor's dorm room. 117 00:06:13,080 --> 00:06:16,320 You can instead just go on the web, which all of us surely take for granted 118 00:06:16,320 --> 00:06:18,390 today, fill out a web-based form. 119 00:06:18,390 --> 00:06:22,020 And then at the time, the proctor in charge of froshims 120 00:06:22,020 --> 00:06:25,380 would get an email confirming who had actually registered for a sport. 121 00:06:25,380 --> 00:06:28,130 And eventually we added CSV files, comma separated values 122 00:06:28,130 --> 00:06:30,560 files like spreadsheets, in which the data was saved. 123 00:06:30,560 --> 00:06:32,190 Then we had this really cool tournament bracket 124 00:06:32,190 --> 00:06:35,106 thing, which was all very dynamic and impressive I'm sure at the time. 125 00:06:35,106 --> 00:06:38,410 But we'll focus on really just the fundamentals today. 126 00:06:38,410 --> 00:06:39,520 So how do we get there? 127 00:06:39,520 --> 00:06:42,120 Well, let me go ahead and open up CS50 IDE 128 00:06:42,120 --> 00:06:46,080 and propose that if we want to make a website, a web 129 00:06:46,080 --> 00:06:50,010 application really, and by application I mean something that does have logic. 130 00:06:50,010 --> 00:06:52,510 By website, it's generally something that's static. 131 00:06:52,510 --> 00:06:53,700 So that's what a web app is. 132 00:06:53,700 --> 00:06:56,783 It's something that changes based on who's using it, when you're using it, 133 00:06:56,783 --> 00:06:58,050 and what you're doing with it. 134 00:06:58,050 --> 00:07:02,190 Let me go ahead, and in the most annoying tedious way possible, 135 00:07:02,190 --> 00:07:05,340 implement a web application using Python. 136 00:07:05,340 --> 00:07:11,429 So I'm going to go ahead and open a file called serve.pie to serve up a website. 137 00:07:11,429 --> 00:07:13,720 And I'm going to go ahead and import some library code. 138 00:07:13,720 --> 00:07:19,110 So from HTTP server, import something called base HTTP request handler 139 00:07:19,110 --> 00:07:21,510 and also something called HTTP server. 140 00:07:21,510 --> 00:07:24,220 And then I'm going to go ahead and use this keyword class, which 141 00:07:24,220 --> 00:07:36,750 is HTTP server, server request, request handler, base HTTP request handler-- 142 00:07:36,750 --> 00:07:37,641 handler. 143 00:07:37,641 --> 00:07:39,640 Then I'm going to go ahead and in here implement 144 00:07:39,640 --> 00:07:44,770 a function called def do_GET, which implies-- 145 00:07:44,770 --> 00:07:48,160 this is a function in Python that should be called anytime a user 146 00:07:48,160 --> 00:07:51,970 visits my web server via GET, the type of verb 147 00:07:51,970 --> 00:07:54,115 that we've talked about in the context of the web. 148 00:07:54,115 --> 00:07:56,620 So suppose that my only goal here is to make 149 00:07:56,620 --> 00:08:00,160 a web-based application that for the moment just says hello world. 150 00:08:00,160 --> 00:08:03,320 We know how to do this with HTML, but with HTML that's just a file. 151 00:08:03,320 --> 00:08:07,540 Let's write a program that not just prints hello world, 152 00:08:07,540 --> 00:08:10,180 but generates a web page containing hello world. 153 00:08:10,180 --> 00:08:11,800 So the way I might do this is this. 154 00:08:11,800 --> 00:08:15,400 I can literally say self, because self refers to the web server in this case. 155 00:08:15,400 --> 00:08:18,429 And I can go ahead and send a response code of 200, 156 00:08:18,429 --> 00:08:20,470 just kind of presumptuously assuming everything's 157 00:08:20,470 --> 00:08:22,000 going to be OK in a moment. 158 00:08:22,000 --> 00:08:24,550 Then I'm going to go ahead and send a header, which 159 00:08:24,550 --> 00:08:26,500 recall, we've discussed briefly in the past, 160 00:08:26,500 --> 00:08:31,900 whereby this header is going to be content type and its value 161 00:08:31,900 --> 00:08:34,780 is going to be text HTML, which is a clue to browser 162 00:08:34,780 --> 00:08:37,990 that it's receiving not a GIF, or JPEG, or something else, 163 00:08:37,990 --> 00:08:39,402 but an actual HTML page. 164 00:08:39,402 --> 00:08:42,110 And then I'm going to go ahead and say that's it for the headers. 165 00:08:42,110 --> 00:08:44,830 I'm going to call function called end headers. 166 00:08:44,830 --> 00:08:47,500 And then lastly, I'm going to use Python code 167 00:08:47,500 --> 00:08:49,704 to dynamically generate my website. 168 00:08:49,704 --> 00:08:51,370 Now, what does the website have to have? 169 00:08:51,370 --> 00:08:54,411 Just hello world at the end of the day, but there's a whole bunch of html 170 00:08:54,411 --> 00:08:56,360 we need to do in order to get to that point. 171 00:08:56,360 --> 00:09:00,790 So I'm going to use a function called wfile write in order 172 00:09:00,790 --> 00:09:02,180 to write out the following. 173 00:09:02,180 --> 00:09:05,490 Let me go ahead and write out doctype-- 174 00:09:05,490 --> 00:09:09,730 whoops, exclamation point doctype HTML. 175 00:09:09,730 --> 00:09:14,905 Then let me go ahead and do the same thing, wfile.write, let me go ahead 176 00:09:14,905 --> 00:09:17,530 and copy paste this moving forward, which, of course, is always 177 00:09:17,530 --> 00:09:18,520 a bad instinct. 178 00:09:18,520 --> 00:09:24,070 Then let me go ahead and output HTML lang equals en for English. 179 00:09:24,070 --> 00:09:26,840 And notice I'm using single quotes inside my double quotes 180 00:09:26,840 --> 00:09:28,600 so that Python doesn't get confused. 181 00:09:28,600 --> 00:09:33,130 Then let me go ahead and output head tag here. 182 00:09:33,130 --> 00:09:36,340 Then what comes after the head tag typically? 183 00:09:36,340 --> 00:09:38,140 Yeah, so usually title lately. 184 00:09:38,140 --> 00:09:44,080 So title will be like hello title, close the title tag. 185 00:09:44,080 --> 00:09:49,290 And now we're going to go ahead and what comes after title? 186 00:09:49,290 --> 00:09:51,750 Close head, I think, if I'm doing this right. 187 00:09:51,750 --> 00:09:55,350 And then after this we probably have a body. 188 00:09:55,350 --> 00:09:58,380 And then oh my God, this is the worst way to build a website. 189 00:09:58,380 --> 00:10:02,250 But let's go ahead and now say something simple like hello world. 190 00:10:02,250 --> 00:10:06,960 And now let's go in here and say something like body. 191 00:10:06,960 --> 00:10:13,340 And then finally, let's go ahead and end the page and say slash HTML. 192 00:10:13,340 --> 00:10:14,100 Done. 193 00:10:14,100 --> 00:10:17,520 OK, and now I actually need to configure the server to listen on a port. 194 00:10:17,520 --> 00:10:21,150 So let me go ahead and define a TCP port of 8080, which we've been using. 195 00:10:21,150 --> 00:10:23,860 Let me go ahead and define the server's address as being, 196 00:10:23,860 --> 00:10:28,710 oh 0.0.0.0, which is what the IDE uses by default, like a lot of servers. 197 00:10:28,710 --> 00:10:32,400 And then let me create the web server, HTTP server. 198 00:10:32,400 --> 00:10:43,060 server_address HTTP server request handler, httpd.serve_forever. 199 00:10:43,060 --> 00:10:45,900 OK, that is how you make a web-based application that 200 00:10:45,900 --> 00:10:47,972 dynamically generates HTML. 201 00:10:47,972 --> 00:10:51,180 In retrospect, I really regret typing all of that out because the whole point 202 00:10:51,180 --> 00:10:53,250 now is to throw this code away. 203 00:10:53,250 --> 00:10:55,710 Like, this is why frameworks exist. 204 00:10:55,710 --> 00:11:00,390 If my goal quite simply at hand is to write Python code that dynamically 205 00:11:00,390 --> 00:11:04,680 generates HTML, then calling lots of functions like write, 206 00:11:04,680 --> 00:11:08,730 which is essentially the equivalent of print in this context, is just tedious. 207 00:11:08,730 --> 00:11:11,430 I got bored writing it, I accomplished so terribly 208 00:11:11,430 --> 00:11:12,940 little at the end of the day. 209 00:11:12,940 --> 00:11:15,820 And so frameworks exist to make our lives easier. 210 00:11:15,820 --> 00:11:19,020 But what's going on underneath the hood is exactly this. 211 00:11:19,020 --> 00:11:21,720 When we start using this framework called Flask, 212 00:11:21,720 --> 00:11:24,460 it's just going to make all of this automated for us. 213 00:11:24,460 --> 00:11:27,330 It's going to make it easier to specify the IP address that you 214 00:11:27,330 --> 00:11:29,190 want to run your web server on, it's going 215 00:11:29,190 --> 00:11:32,106 to make it easier to specify the port number that you want your server 216 00:11:32,106 --> 00:11:35,010 to be listening on, and it's going to make it easier 217 00:11:35,010 --> 00:11:38,850 to respond to get requests because Flask will 218 00:11:38,850 --> 00:11:44,010 take care of the implementation of some function like this one called do get. 219 00:11:44,010 --> 00:11:46,260 So all of this is there underneath the hood, 220 00:11:46,260 --> 00:11:50,520 but the flask framework gives us essentially an abstraction 221 00:11:50,520 --> 00:11:51,640 on top of that. 222 00:11:51,640 --> 00:11:53,170 So what do I actually mean by that? 223 00:11:53,170 --> 00:11:57,366 If we want to distill this now into a simpler web application, 224 00:11:57,366 --> 00:11:58,740 first let's go ahead and do this. 225 00:11:58,740 --> 00:12:03,450 Let me go ahead and open up a terminal window and let me go into my code 226 00:12:03,450 --> 00:12:07,590 here and go ahead and run Python of serve.py. 227 00:12:07,590 --> 00:12:10,030 And you'll see nothing seems to be happening just yet. 228 00:12:10,030 --> 00:12:11,940 So I'm going to go to cs50 IDE web server 229 00:12:11,940 --> 00:12:15,999 to open up a tab containing the web server that I'm now running. 230 00:12:15,999 --> 00:12:17,040 And you'll see that's it. 231 00:12:17,040 --> 00:12:18,998 That's the only thing I accomplished right now. 232 00:12:18,998 --> 00:12:21,900 It's not dynamic to be sure, but there is code and Python code 233 00:12:21,900 --> 00:12:25,140 there with which I could actually do something dynamically. 234 00:12:25,140 --> 00:12:28,980 But let's instead do this now with Flask, this framework 235 00:12:28,980 --> 00:12:30,480 that seems to make our lives easier. 236 00:12:30,480 --> 00:12:34,945 I'm going to go ahead and make a program called application.py, which 237 00:12:34,945 --> 00:12:35,820 is just a convention. 238 00:12:35,820 --> 00:12:37,400 I could call it anything I want. 239 00:12:37,400 --> 00:12:39,400 And I'm going to go ahead and say the following. 240 00:12:39,400 --> 00:12:42,270 Let's first go ahead and import this framework called Flask. 241 00:12:42,270 --> 00:12:45,090 And specifically import capitalized flask, which 242 00:12:45,090 --> 00:12:46,710 is the name of the framework itself. 243 00:12:46,710 --> 00:12:49,650 And then let me preemptively import a couple of functions 244 00:12:49,650 --> 00:12:53,337 called render template and then this special global variable called request. 245 00:12:53,337 --> 00:12:55,920 You would only know to do this from reading the documentation. 246 00:12:55,920 --> 00:12:58,320 But now let me go ahead and say, hey Flask, 247 00:12:58,320 --> 00:13:01,500 could you please give me a web application? 248 00:13:01,500 --> 00:13:02,610 And this is copy paste. 249 00:13:02,610 --> 00:13:04,770 You need this at the top of any Flask application, 250 00:13:04,770 --> 00:13:07,200 and it just means turn this file-- 251 00:13:07,200 --> 00:13:11,102 application.py-- into a web application. 252 00:13:11,102 --> 00:13:13,060 Then lastly, I'm going to go ahead and do this. 253 00:13:13,060 --> 00:13:15,630 I'm going to tell Flask I want to build an app that 254 00:13:15,630 --> 00:13:20,520 has a route that's listening for slash inside of that virtual envelope. 255 00:13:20,520 --> 00:13:25,950 And whenever, Flask, you see a request for slash from some user, 256 00:13:25,950 --> 00:13:29,550 go ahead and call this function which I arbitrarily called index, 257 00:13:29,550 --> 00:13:31,920 but I could call it foo, or bar, or whatever. 258 00:13:31,920 --> 00:13:36,920 And what I want you to do is this, return hello world. 259 00:13:36,920 --> 00:13:38,280 And that's it. 260 00:13:38,280 --> 00:13:41,450 So all of those other lines I tediously wrote out a moment ago 261 00:13:41,450 --> 00:13:44,510 are now distilled into just 7 lines, which none of which 262 00:13:44,510 --> 00:13:47,010 are completely obvious how they work just yet. 263 00:13:47,010 --> 00:13:50,330 But if you assume that this means give me access to the library, 264 00:13:50,330 --> 00:13:53,930 turned my file into a web application, and listen now 265 00:13:53,930 --> 00:13:57,109 for get requests on slash, it kind of makes sense 266 00:13:57,109 --> 00:13:59,900 and fits into the mental model that we introduced a couple of weeks 267 00:13:59,900 --> 00:14:02,510 ago with HTML and CSS itself. 268 00:14:02,510 --> 00:14:06,140 And to run this server, what I'm going to do now in my hello directory, which 269 00:14:06,140 --> 00:14:09,050 is where a online copy of this is on the course's website, 270 00:14:09,050 --> 00:14:11,530 I'm going to go ahead and quite simply say Flask run. 271 00:14:11,530 --> 00:14:14,450 So Flask is not only a framework or code that you have access 272 00:14:14,450 --> 00:14:17,270 to as free and open source code, but it's also 273 00:14:17,270 --> 00:14:19,970 a program you can run at the command line that also figures out 274 00:14:19,970 --> 00:14:22,659 how to turn the server on and just run it forever. 275 00:14:22,659 --> 00:14:25,700 You're going to see some diagnostic output at first glance, most of which 276 00:14:25,700 --> 00:14:26,930 you don't have to care about. 277 00:14:26,930 --> 00:14:29,000 But there will be a few URL that's spit out which 278 00:14:29,000 --> 00:14:30,650 is based on your own user name. 279 00:14:30,650 --> 00:14:34,380 Mine today is jharvard 3 just for demonstration purposes. 280 00:14:34,380 --> 00:14:37,460 And if you click on that URL and then click Open, 281 00:14:37,460 --> 00:14:42,014 you'll see now this version of the same application doing just this. 282 00:14:42,014 --> 00:14:43,430 Now, I'm kind of cheating, though. 283 00:14:43,430 --> 00:14:47,510 Because if I open up Chrome and view my page source, notice that of course 284 00:14:47,510 --> 00:14:51,191 I'm cheating because all I've done is print out hello world. 285 00:14:51,191 --> 00:14:52,940 And if I view the source of this page, I'm 286 00:14:52,940 --> 00:14:57,290 literally only going to say hello world and no actual HTML 287 00:14:57,290 --> 00:15:00,890 because I literally didn't type out any HTML in my file. 288 00:15:00,890 --> 00:15:04,007 But it turns out that Flask makes this easy, as well. 289 00:15:04,007 --> 00:15:06,590 So let me go ahead and stop the server here for just a moment. 290 00:15:06,590 --> 00:15:08,330 Control-c is your friend, it gets you out 291 00:15:08,330 --> 00:15:10,340 of whatever program is actually running. 292 00:15:10,340 --> 00:15:12,020 And let me go ahead and do this. 293 00:15:12,020 --> 00:15:14,870 Let me go ahead and not just return quote-unquote hello world 294 00:15:14,870 --> 00:15:16,560 as a hardcoded value. 295 00:15:16,560 --> 00:15:22,760 Let me go ahead and return the rendering of a template called index.html. 296 00:15:22,760 --> 00:15:24,890 And so this is a feature of Flask, too. 297 00:15:24,890 --> 00:15:27,100 If you want to separate your logic-- 298 00:15:27,100 --> 00:15:29,780 your controller-- from your HTML-- 299 00:15:29,780 --> 00:15:33,500 your view-- you literally put the former in application.pi, 300 00:15:33,500 --> 00:15:36,500 and you put the latter in an HTML file like this. 301 00:15:36,500 --> 00:15:38,840 And you tell the controller code-- 302 00:15:38,840 --> 00:15:41,780 application.py-- show the user, to render 303 00:15:41,780 --> 00:15:44,870 for the user the index.html file. 304 00:15:44,870 --> 00:15:46,400 So where do I put this? 305 00:15:46,400 --> 00:15:50,450 The convention would be to make a directory called templates. 306 00:15:50,450 --> 00:15:55,532 And then in that directory, go ahead and put a file called index.html. 307 00:15:55,532 --> 00:15:57,740 And if I go ahead and open up the file that I already 308 00:15:57,740 --> 00:16:01,344 created in advance of class here, let me just show you what this looks like. 309 00:16:01,344 --> 00:16:03,260 And then we'll take a look at it in a browser. 310 00:16:03,260 --> 00:16:09,050 Here is HTML now with a pretty fancy feature 311 00:16:09,050 --> 00:16:11,660 that we're about to reveal the utility of. 312 00:16:11,660 --> 00:16:16,170 What jumps out at you is new in this file? 313 00:16:16,170 --> 00:16:18,220 AUDIENCE: Two curly braces on the name. 314 00:16:18,220 --> 00:16:20,140 DAVID MALAN: Yeah, two curly braces. 315 00:16:20,140 --> 00:16:22,960 And somehow or other that used to be saying world, 316 00:16:22,960 --> 00:16:25,390 but in my final version of this I actually 317 00:16:25,390 --> 00:16:27,855 am hinting at some more powerful capabilities. 318 00:16:27,855 --> 00:16:29,980 This kind of looks like a placeholder, if you will. 319 00:16:29,980 --> 00:16:31,750 Maybe someone's actual name. 320 00:16:31,750 --> 00:16:34,760 And here's where the power of something like Flask comes into play. 321 00:16:34,760 --> 00:16:37,520 It makes it really easy to do something like this. 322 00:16:37,520 --> 00:16:39,520 So let me go ahead and actually turn this 323 00:16:39,520 --> 00:16:41,470 into something a little more interesting. 324 00:16:41,470 --> 00:16:43,300 Let me go into application.py. 325 00:16:43,300 --> 00:16:47,860 And before I actually render this HTML file, let me go ahead and do this. 326 00:16:47,860 --> 00:16:50,960 Let me go ahead and declare a variable called name. 327 00:16:50,960 --> 00:16:54,040 And let me go ahead and check the incoming request, 328 00:16:54,040 --> 00:16:56,530 the inside of that virtual envelope. 329 00:16:56,530 --> 00:17:01,390 Let me check its arguments or any of the HTTP parameters that were passed in 330 00:17:01,390 --> 00:17:05,200 and try to get something called name like this. 331 00:17:05,200 --> 00:17:07,930 Let me go ahead and save that and then notice this. 332 00:17:07,930 --> 00:17:10,117 Render template takes multiple arguments. 333 00:17:10,117 --> 00:17:12,950 The first one should be the name of the template you want to render. 334 00:17:12,950 --> 00:17:15,369 But if you want to pass in data dynamically, 335 00:17:15,369 --> 00:17:19,060 you can use named parameters in Python. 336 00:17:19,060 --> 00:17:22,359 Recall from last week that you can do things like this, x equals y, 337 00:17:22,359 --> 00:17:23,560 and z equals w. 338 00:17:23,560 --> 00:17:26,470 You can pass in the names of the things you want to pass in 339 00:17:26,470 --> 00:17:28,490 and their corresponding values. 340 00:17:28,490 --> 00:17:35,080 So if I want to pass in a name variable and set it equal to the name variable 341 00:17:35,080 --> 00:17:38,200 that I just defined, watch what we can do here. 342 00:17:38,200 --> 00:17:41,110 Let me go back to my console. 343 00:17:41,110 --> 00:17:45,940 Let me go ahead and rerun in my hello directory, which is available online, 344 00:17:45,940 --> 00:17:47,470 Flask run. 345 00:17:47,470 --> 00:17:51,310 And now let me go over to this where it previously said hello world. 346 00:17:51,310 --> 00:17:54,040 Let me now, just like with our Google example a couple of weeks 347 00:17:54,040 --> 00:17:57,730 ago, type in not q equals cats, which is what we did last time, 348 00:17:57,730 --> 00:18:01,720 but maybe name equals David to simulate a get request. 349 00:18:01,720 --> 00:18:06,530 And if I did everything right, when I hit Enter I now see this dynamically. 350 00:18:06,530 --> 00:18:10,000 And if I change this now from David to, say, Veronica, of course, 351 00:18:10,000 --> 00:18:11,830 this is going to dynamically output this. 352 00:18:11,830 --> 00:18:14,170 Can someone now try to break my code? 353 00:18:14,170 --> 00:18:19,950 Propose an input that I should try to see if I messed up somewhere. 354 00:18:19,950 --> 00:18:21,607 AUDIENCE: No entry. 355 00:18:21,607 --> 00:18:22,690 DAVID MALAN: OK, no input. 356 00:18:22,690 --> 00:18:24,760 Or what's that? 357 00:18:24,760 --> 00:18:26,375 say again? 358 00:18:26,375 --> 00:18:28,000 Name equals name, I like that one, too. 359 00:18:28,000 --> 00:18:29,940 So let's try that, name equals name. 360 00:18:29,940 --> 00:18:34,840 So OK, I mean it's kind of maybe like a grammatical bug or semantic bug, 361 00:18:34,840 --> 00:18:37,450 but not really a code bug per se. 362 00:18:37,450 --> 00:18:38,470 That's just user error. 363 00:18:38,470 --> 00:18:40,570 But what if I just get rid of it? 364 00:18:40,570 --> 00:18:42,130 OK, that just looks a little stupid. 365 00:18:42,130 --> 00:18:44,796 So an aesthetic bug, but we should probably start handling this. 366 00:18:44,796 --> 00:18:46,600 What if I get rid of name altogether? 367 00:18:46,600 --> 00:18:47,620 Interesting. 368 00:18:47,620 --> 00:18:50,680 It seems that my final version actually has some built in functionality. 369 00:18:50,680 --> 00:18:52,360 So where is that coming from? 370 00:18:52,360 --> 00:18:53,750 Well, what if I did this? 371 00:18:53,750 --> 00:18:56,360 It turns out that I could say something like this. 372 00:18:56,360 --> 00:18:59,860 If not name, then go ahead and set name equal to world 373 00:18:59,860 --> 00:19:01,520 would be one way of doing it. 374 00:19:01,520 --> 00:19:04,870 Or I could actually use the function here. 375 00:19:04,870 --> 00:19:07,867 Turns out that this get function can take a default value. 376 00:19:07,867 --> 00:19:09,700 And so if you read the documentation, you'll 377 00:19:09,700 --> 00:19:11,830 see that the second value you provide will be 378 00:19:11,830 --> 00:19:13,870 used if the user hasn't provided one. 379 00:19:13,870 --> 00:19:17,230 And so indeed, if I reload now and see nothing, I get world. 380 00:19:17,230 --> 00:19:21,980 And if I instead do name equals, say, Brian, I get that dynamic output. 381 00:19:21,980 --> 00:19:26,290 And so when I say web application, this is just a hint of what I mean. 382 00:19:26,290 --> 00:19:28,660 This is dynamically generated content. 383 00:19:28,660 --> 00:19:31,400 It's not hardcoded, because it's actually coming from the user. 384 00:19:31,400 --> 00:19:35,784 So when Google implements its slash search web application, 385 00:19:35,784 --> 00:19:37,450 this is the kind of thing they're doing. 386 00:19:37,450 --> 00:19:38,650 It's way more involved, of course. 387 00:19:38,650 --> 00:19:41,525 They're searching a database, looking for cats, and dogs, or whatever 388 00:19:41,525 --> 00:19:44,140 it is you're searching for and then generating HTML. 389 00:19:44,140 --> 00:19:46,840 But notice with just this simple approach 390 00:19:46,840 --> 00:19:50,800 can we ourselves generate any HTML we want dynamically. 391 00:19:50,800 --> 00:19:52,870 Because all we have to do in that template 392 00:19:52,870 --> 00:19:56,980 called index.html is exactly this. 393 00:19:56,980 --> 00:19:59,800 Hello, comma, and then a placeholder where 394 00:19:59,800 --> 00:20:01,750 name is the variable you're passing in. 395 00:20:01,750 --> 00:20:04,000 And so to be clear, it doesn't have to be called name. 396 00:20:04,000 --> 00:20:07,190 I could do something like foo, which would be a little nonsensical. 397 00:20:07,190 --> 00:20:11,100 But if I do that, the variable I plug in needs to be called foo here. 398 00:20:11,100 --> 00:20:13,060 And so there's a one to one correspondence 399 00:20:13,060 --> 00:20:16,510 between the things before the equal signs and where they get 400 00:20:16,510 --> 00:20:19,060 plugged in down here. 401 00:20:19,060 --> 00:20:22,630 Any questions, then, on this simple example, but building block? 402 00:20:22,630 --> 00:20:23,584 Yeah? 403 00:20:23,584 --> 00:20:27,730 AUDIENCE: [INAUDIBLE] dynamically generated. 404 00:20:27,730 --> 00:20:28,480 DAVID MALAN: Sure. 405 00:20:28,480 --> 00:20:34,360 By dynamically generated, I mean I have not written in advance by typing it out 406 00:20:34,360 --> 00:20:37,840 manually a web page that says hello David, or hello Brian, 407 00:20:37,840 --> 00:20:40,370 or hello Veronica. 408 00:20:40,370 --> 00:20:45,070 Those pages are all generated dynamically based on user input. 409 00:20:45,070 --> 00:20:46,540 I wrote most of those pages. 410 00:20:46,540 --> 00:20:49,870 I wrote everything up into and after the comma, but then-- sorry, 411 00:20:49,870 --> 00:20:54,160 up to the comma, but then the names are dynamically added. 412 00:20:54,160 --> 00:20:54,950 Good question. 413 00:20:54,950 --> 00:20:57,820 Other questions? 414 00:20:57,820 --> 00:20:58,670 All right. 415 00:20:58,670 --> 00:21:04,070 So why don't we rewind to 1997 or so and see 416 00:21:04,070 --> 00:21:07,280 if we can't build a more dynamic web application that actually allow 417 00:21:07,280 --> 00:21:09,680 students to register for something that's 418 00:21:09,680 --> 00:21:12,500 a little more compelling than just providing their name? 419 00:21:12,500 --> 00:21:17,150 So let me go ahead and open up froshim0, which is the first larger scale 420 00:21:17,150 --> 00:21:18,860 application we have here today. 421 00:21:18,860 --> 00:21:21,290 And notice that I have a few files. 422 00:21:21,290 --> 00:21:24,282 So already things are going to escalate quickly whereby we're 423 00:21:24,282 --> 00:21:26,240 going to suddenly introduce multiple templates, 424 00:21:26,240 --> 00:21:28,710 but we'll do this in order to solve a problem. 425 00:21:28,710 --> 00:21:31,880 But first let me go ahead and open up application,py, 426 00:21:31,880 --> 00:21:35,630 which just like your main function in C is kind of the entry point now 427 00:21:35,630 --> 00:21:37,430 to a web-based application. 428 00:21:37,430 --> 00:21:40,550 So notice that-- let's start like this. 429 00:21:40,550 --> 00:21:44,090 Let me go ahead and delete that and start from the beginning here. 430 00:21:44,090 --> 00:21:47,930 Let's go ahead and do this. 431 00:21:47,930 --> 00:21:52,910 In froshim0, we have this default route of slash, 432 00:21:52,910 --> 00:21:55,044 and notice that it's going to render index.html. 433 00:21:55,044 --> 00:21:56,960 So when you start to read someone else's code, 434 00:21:56,960 --> 00:21:58,710 you kind of follow these breadcrumbs. 435 00:21:58,710 --> 00:22:01,670 So let me go ahead and open the same folder, froshim0. 436 00:22:01,670 --> 00:22:03,977 Let me go into-- 437 00:22:03,977 --> 00:22:06,560 let me go ahead, rather, let's do this from scratch, actually. 438 00:22:06,560 --> 00:22:07,250 Let's do this. 439 00:22:07,250 --> 00:22:13,490 Index.html, and let me do the familiar doctype HTML. 440 00:22:13,490 --> 00:22:16,850 Then let me go ahead and do an HTML tag here, it finishes my thought for me. 441 00:22:16,850 --> 00:22:22,070 The head tag here, the title tag here, froshim0 will be the title here. 442 00:22:22,070 --> 00:22:23,660 Let me go ahead and create a body. 443 00:22:23,660 --> 00:22:26,570 And now for this web page, I want to go ahead 444 00:22:26,570 --> 00:22:30,990 and have a few things via which the user can actually register for froshim. 445 00:22:30,990 --> 00:22:32,990 So let me go ahead and have just some title text 446 00:22:32,990 --> 00:22:36,620 here, like register for froshims like I did back in the day. 447 00:22:36,620 --> 00:22:38,840 Then let me go ahead and start a form tag. 448 00:22:38,840 --> 00:22:41,090 And then in here, what information might a student 449 00:22:41,090 --> 00:22:44,326 want to provide when registering for something like a sports team? 450 00:22:44,326 --> 00:22:45,100 AUDIENCE: Name. 451 00:22:45,100 --> 00:22:46,599 DAVID MALAN: OK, the student's name. 452 00:22:46,599 --> 00:22:50,120 So input type equals text. 453 00:22:50,120 --> 00:22:53,149 The name of this input probably shouldn't be something generic like q, 454 00:22:53,149 --> 00:22:55,190 it should probably be more descriptive like name. 455 00:22:55,190 --> 00:22:57,530 So its a little weird looking, but name equals name. 456 00:22:57,530 --> 00:22:58,550 And we'll go ahead and do this. 457 00:22:58,550 --> 00:23:00,258 And if we really want to be fancy, we can 458 00:23:00,258 --> 00:23:04,100 do like a placeholder text of name just to in light gray text show the user 459 00:23:04,100 --> 00:23:05,030 what we want. 460 00:23:05,030 --> 00:23:07,040 And then back in the day, minimally the students 461 00:23:07,040 --> 00:23:09,960 registering for sports had to provide their dorm, 462 00:23:09,960 --> 00:23:11,810 so the building in which they lived. 463 00:23:11,810 --> 00:23:14,010 So in HTML, we've got a bunch of input types. 464 00:23:14,010 --> 00:23:17,320 We've got text boxes, turns out there's text areas which are even bigger, 465 00:23:17,320 --> 00:23:23,171 check boxes, radio buttons, what's most apt perhaps for choosing your dorm? 466 00:23:23,171 --> 00:23:24,170 AUDIENCE: Dropdown list. 467 00:23:24,170 --> 00:23:28,520 DAVID MALAN: Like a dropdown list, otherwise called a menu. 468 00:23:28,520 --> 00:23:31,155 But which tag? 469 00:23:31,155 --> 00:23:32,330 AUDIENCE: Container? 470 00:23:32,330 --> 00:23:34,913 DAVID MALAN: Not a container, a little more precise than that. 471 00:23:34,913 --> 00:23:37,970 With what tag can you generate a dropdown list 472 00:23:37,970 --> 00:23:39,836 if you've done this before in HTML? 473 00:23:39,836 --> 00:23:40,730 AUDIENCE: Select. 474 00:23:40,730 --> 00:23:41,563 DAVID MALAN: Select. 475 00:23:41,563 --> 00:23:45,710 So it's not perfectly clearly named, but it's, indeed, a select menu by name. 476 00:23:45,710 --> 00:23:47,040 And so I can actually do this. 477 00:23:47,040 --> 00:23:50,510 Select, and the name of this field will be dorm, for instance. 478 00:23:50,510 --> 00:23:53,920 And then inside of this I'm going to go ahead and have a few options. 479 00:23:53,920 --> 00:23:58,130 So one option might be let's say Apley Court, which 480 00:23:58,130 --> 00:24:01,100 is one of the buildings in which freshmen live. 481 00:24:01,100 --> 00:24:03,432 There might be another one called Canoday, 482 00:24:03,432 --> 00:24:05,390 and then there's going to be bunches of others. 483 00:24:05,390 --> 00:24:08,510 And then notice, too, if you've never used a select menu, which you wouldn't 484 00:24:08,510 --> 00:24:10,801 have really had occasion to yet unless you've done this 485 00:24:10,801 --> 00:24:14,300 before, these options also have to have values, which for my purposes 486 00:24:14,300 --> 00:24:16,350 are going to be exactly the same. 487 00:24:16,350 --> 00:24:20,780 But whereas what's between the tags is what the human sees, 488 00:24:20,780 --> 00:24:24,260 it's what's between these quotes as the value of value 489 00:24:24,260 --> 00:24:26,480 that the computer actually sees. 490 00:24:26,480 --> 00:24:29,270 So these are the words that populate the dropdown menu, 491 00:24:29,270 --> 00:24:32,600 these are the values that actually gets stuffed into the virtual envelope 492 00:24:32,600 --> 00:24:35,420 that the student him or herself actually see. 493 00:24:35,420 --> 00:24:37,640 So let me go ahead and save this. 494 00:24:37,640 --> 00:24:41,316 Let me go ahead and now open up my console. 495 00:24:41,316 --> 00:24:43,190 And I'm going to borrow a little code just so 496 00:24:43,190 --> 00:24:45,470 that we can do this from scratch here. 497 00:24:45,470 --> 00:24:51,950 So let me go ahead and grab from froshim0 my application.py file 498 00:24:51,950 --> 00:24:55,430 and go into my workspace. 499 00:24:55,430 --> 00:24:59,420 So let me go ahead now and run Flask run wherein 500 00:24:59,420 --> 00:25:01,370 I have this application.py file. 501 00:25:01,370 --> 00:25:04,190 I'm going to see the URL at which my code now lives. 502 00:25:04,190 --> 00:25:07,220 And if I open this up, I'm going to see an internal server error. 503 00:25:07,220 --> 00:25:11,180 So intended at some point because internal server error, recall, 504 00:25:11,180 --> 00:25:14,685 was one of the more arcane status codes, 500, that you probably 505 00:25:14,685 --> 00:25:17,810 have not seen unless you're visiting a website where something has actually 506 00:25:17,810 --> 00:25:18,930 going wrong. 507 00:25:18,930 --> 00:25:21,500 So how do I begin to figure out what has gone wrong now 508 00:25:21,500 --> 00:25:24,800 that I'm actually writing code and not just writing hard coded HTML? 509 00:25:24,800 --> 00:25:27,350 Well, all of the clues are going to be found 510 00:25:27,350 --> 00:25:30,090 here inside of the console window. 511 00:25:30,090 --> 00:25:33,860 So when you're running Flask you are running a full fledged web server. 512 00:25:33,860 --> 00:25:39,512 You are listening via TCP/IP for incoming requests from users. 513 00:25:39,512 --> 00:25:42,470 And so what you'll see in the console is not just the diagnostic output 514 00:25:42,470 --> 00:25:46,490 when you first start Flask, but you're going to see all of the error messages 515 00:25:46,490 --> 00:25:48,669 that might actually happen thereafter. 516 00:25:48,669 --> 00:25:50,210 And this is a little cryptic looking. 517 00:25:50,210 --> 00:25:53,110 Frankly, it's overwhelming to see this text at first glance. 518 00:25:53,110 --> 00:25:56,150 But whereas in Clang and in C it generally 519 00:25:56,150 --> 00:25:59,480 helps to look at the very top, sometimes the error messages 520 00:25:59,480 --> 00:26:02,250 here in this context of Flask are kind of toward the bottom. 521 00:26:02,250 --> 00:26:04,310 And here we have template not found. 522 00:26:04,310 --> 00:26:06,829 Template because it can't find index.html. 523 00:26:06,829 --> 00:26:08,370 And that's just because I screwed up. 524 00:26:08,370 --> 00:26:11,090 So let me actually exit Flask by typing control-c. 525 00:26:11,090 --> 00:26:14,690 And if I type ls in my directory, notice that I haven't quite 526 00:26:14,690 --> 00:26:16,440 practiced what I've preached. 527 00:26:16,440 --> 00:26:19,220 It's perhaps a little subtle, but I haven't organized myself 528 00:26:19,220 --> 00:26:19,950 in the right way. 529 00:26:19,950 --> 00:26:23,220 What have I done wrong? 530 00:26:23,220 --> 00:26:24,320 Yeah? 531 00:26:24,320 --> 00:26:25,190 AUDIENCE: Didn't make a templates directory. 532 00:26:25,190 --> 00:26:26,820 DAVID MALAN: Yeah, it's kind of a silly mistake. 533 00:26:26,820 --> 00:26:28,290 I didn't make a templates directory. 534 00:26:28,290 --> 00:26:30,081 So you can do this in a few different ways. 535 00:26:30,081 --> 00:26:32,460 By the folder icon up here, you can create a new folder 536 00:26:32,460 --> 00:26:34,290 by right clicking or control clicking. 537 00:26:34,290 --> 00:26:37,290 Or in Linux you can do make dir for make directory. 538 00:26:37,290 --> 00:26:40,140 And so I can do make dir templates enter. 539 00:26:40,140 --> 00:26:43,410 And then I can move my index.html file, which 540 00:26:43,410 --> 00:26:47,850 I wrote a moment ago, into my templates directory by just using mv for move. 541 00:26:47,850 --> 00:26:52,020 And now I can go ahead and run Flask run, cross my fingers, 542 00:26:52,020 --> 00:26:54,960 go back to the browser tab and click reload, 543 00:26:54,960 --> 00:26:57,090 and voila, now I actually see the form. 544 00:26:57,090 --> 00:26:58,480 So have these kinds of instincts. 545 00:26:58,480 --> 00:27:01,188 I didn't actually intend that, but I forgot to create the folder. 546 00:27:01,188 --> 00:27:02,220 I got this server error. 547 00:27:02,220 --> 00:27:03,690 You don't have to just stare at the browser, which 548 00:27:03,690 --> 00:27:05,273 is not going to have much information. 549 00:27:05,273 --> 00:27:07,740 But if you look at the console, the terminal window 550 00:27:07,740 --> 00:27:11,710 that you have control over will you see those clang-like error messages. 551 00:27:11,710 --> 00:27:13,290 So here we have a basic HTML form. 552 00:27:13,290 --> 00:27:15,456 It's not complete because I didn't bother typing out 553 00:27:15,456 --> 00:27:18,090 all of the dorm names, but I do have an input of type text 554 00:27:18,090 --> 00:27:19,530 as well as the Select menu. 555 00:27:19,530 --> 00:27:22,260 And I'm also kind of missing a key detail, it seems. 556 00:27:22,260 --> 00:27:24,232 What should I probably add to this form? 557 00:27:24,232 --> 00:27:25,740 AUDIENCE: Where you're selecting. 558 00:27:25,740 --> 00:27:26,670 DAVID MALAN: Well, I'm selecting-- 559 00:27:26,670 --> 00:27:29,545 I could be selecting dorm, so I could clean this up in a couple ways. 560 00:27:29,545 --> 00:27:31,864 I also am missing a Submit button. 561 00:27:31,864 --> 00:27:33,780 Now, it turns out you could probably hit Enter 562 00:27:33,780 --> 00:27:36,571 and it would actually be submitted by default. But we can fix this. 563 00:27:36,571 --> 00:27:38,970 So let me go into index.html. 564 00:27:38,970 --> 00:27:42,410 Let me shrink this tab just a little bit and let me fix both of these things. 565 00:27:42,410 --> 00:27:46,950 So let me go ahead and open up this latest version, which 566 00:27:46,950 --> 00:27:50,450 is now in that templates directory. 567 00:27:50,450 --> 00:27:55,110 Let me go ahead and at the bottom here do an input type equals submit, 568 00:27:55,110 --> 00:27:57,840 the value of which is going to be a register, just to make 569 00:27:57,840 --> 00:27:59,620 clear to the human what's going on. 570 00:27:59,620 --> 00:28:04,260 Let me go ahead and go back to my form, click reload. 571 00:28:04,260 --> 00:28:05,980 And nothing's happened just yet. 572 00:28:05,980 --> 00:28:10,080 And that's because by default when you make changes to some of your files, 573 00:28:10,080 --> 00:28:11,444 Flask is not going to notice. 574 00:28:11,444 --> 00:28:13,485 And we'll fix this actually in the coming problem 575 00:28:13,485 --> 00:28:15,300 set by adding more code and a little more 576 00:28:15,300 --> 00:28:17,130 complexity to automate this for you. 577 00:28:17,130 --> 00:28:20,050 But when in doubt, just control-c to quit flask. 578 00:28:20,050 --> 00:28:23,130 Then go ahead and rerun flask, that will reload all 579 00:28:23,130 --> 00:28:25,140 of your HTML, all of your Python code. 580 00:28:25,140 --> 00:28:28,890 And if I now go back here and click reload, we'll see the Register button. 581 00:28:28,890 --> 00:28:31,030 So there should never be any surprises. 582 00:28:31,030 --> 00:28:35,610 And if there are, just try to get to the diagnosis thereof. 583 00:28:35,610 --> 00:28:38,850 This is also a little unclear, too, to what this menu is. 584 00:28:38,850 --> 00:28:42,180 So it turns out that if you actually create a bogus option like this 585 00:28:42,180 --> 00:28:47,080 that has no value and say something like dorm, you can save this. 586 00:28:47,080 --> 00:28:50,820 Let's go ahead and restart Flask and reload the page here. 587 00:28:50,820 --> 00:28:52,260 You'll see that now you see dorm. 588 00:28:52,260 --> 00:28:56,340 Unfortunately, this is kind of stupid because now dorm 589 00:28:56,340 --> 00:28:58,320 is where you can literally live apparently, 590 00:28:58,320 --> 00:28:59,850 which doesn't quite feel right. 591 00:28:59,850 --> 00:29:01,950 So there's HTML fixes for this too. 592 00:29:01,950 --> 00:29:05,130 I can actually go in here and technically say disabled, 593 00:29:05,130 --> 00:29:06,960 so you can't actually select that. 594 00:29:06,960 --> 00:29:12,209 Now if I rerun Flask and reload, now it still shows it there. 595 00:29:12,209 --> 00:29:15,000 But because I already selected Apley Court, you can see it in gray. 596 00:29:15,000 --> 00:29:16,916 And we can actually be a little more specific, 597 00:29:16,916 --> 00:29:21,360 if you want to not only disable it, but select it by default and then go ahead 598 00:29:21,360 --> 00:29:24,176 and reload the page here, now you'll see hopefully 599 00:29:24,176 --> 00:29:25,550 what's familiar on most websites. 600 00:29:25,550 --> 00:29:27,780 It says dorm, but it's disabled. 601 00:29:27,780 --> 00:29:29,760 And even though the silly checkmark is there, 602 00:29:29,760 --> 00:29:31,722 you're forced to choose an actual dorm. 603 00:29:31,722 --> 00:29:33,930 So these are minor aesthetics, but the kind of things 604 00:29:33,930 --> 00:29:35,440 you now have control over. 605 00:29:35,440 --> 00:29:36,840 So what's going to happen? 606 00:29:36,840 --> 00:29:39,240 I haven't actually specified where this form should 607 00:29:39,240 --> 00:29:42,971 go when I actually register because I'm missing some key details on the form 608 00:29:42,971 --> 00:29:43,470 tag. 609 00:29:43,470 --> 00:29:45,386 And we haven't done this in a couple of weeks. 610 00:29:45,386 --> 00:29:48,480 But when we were playfully reimplementing Google, 611 00:29:48,480 --> 00:29:52,340 what else did we add to the form tag? 612 00:29:52,340 --> 00:29:53,360 What attributes? 613 00:29:53,360 --> 00:29:56,860 614 00:29:56,860 --> 00:29:58,990 Anyone remember? 615 00:29:58,990 --> 00:29:59,870 Yeah. 616 00:29:59,870 --> 00:30:01,940 Oh, say again? 617 00:30:01,940 --> 00:30:04,850 Action, which means what? 618 00:30:04,850 --> 00:30:05,800 AUDIENCE: What to do. 619 00:30:05,800 --> 00:30:06,800 DAVID MALAN: What to do. 620 00:30:06,800 --> 00:30:08,508 All right, so the action we want to take, 621 00:30:08,508 --> 00:30:11,510 even though this is not necessarily perfectly well named, 622 00:30:11,510 --> 00:30:13,875 is where do you want to submit the form to? 623 00:30:13,875 --> 00:30:16,250 And I could actually submit this in a few different ways. 624 00:30:16,250 --> 00:30:18,124 I'm going to go ahead and say, you know what, 625 00:30:18,124 --> 00:30:21,549 submit it to a reasonably named route slash register. 626 00:30:21,549 --> 00:30:23,840 Google, for instance, might have code that instead says 627 00:30:23,840 --> 00:30:25,250 to submit their form to slash search. 628 00:30:25,250 --> 00:30:27,170 But we're not searching for something, we're registering. 629 00:30:27,170 --> 00:30:29,270 So the name of the route is entirely up to us. 630 00:30:29,270 --> 00:30:32,300 And via what method should we submit this information? 631 00:30:32,300 --> 00:30:33,380 What are our two options? 632 00:30:33,380 --> 00:30:34,400 AUDIENCE: Get or post. 633 00:30:34,400 --> 00:30:35,500 DAVID MALAN: Get or post. 634 00:30:35,500 --> 00:30:38,480 Get tends to be the default if you don't mention in links. 635 00:30:38,480 --> 00:30:41,319 Why might you want to use post instead? 636 00:30:41,319 --> 00:30:44,110 AUDIENCE: You want it to go to a database in order to do something. 637 00:30:44,110 --> 00:30:46,943 DAVID MALAN: Yeah, you want it to go to a database and do something. 638 00:30:46,943 --> 00:30:49,450 And the right verb to use there is to post information 639 00:30:49,450 --> 00:30:51,010 as opposed to getting information. 640 00:30:51,010 --> 00:30:54,190 And even more specifically when it comes to privacy, when you use post, 641 00:30:54,190 --> 00:30:56,805 the information doesn't end up in the user's URL, 642 00:30:56,805 --> 00:30:58,930 and therefore doesn't end up in his or her history, 643 00:30:58,930 --> 00:31:02,180 and therefore doesn't end up in a place that siblings, or roommates, or anyone 644 00:31:02,180 --> 00:31:04,014 else can actually see just by poking around. 645 00:31:04,014 --> 00:31:07,013 So we'll, indeed, go ahead, because this is my name, and dorm, and maybe 646 00:31:07,013 --> 00:31:09,202 my phone number, and email, and credit card number, 647 00:31:09,202 --> 00:31:10,660 and the like on some other website. 648 00:31:10,660 --> 00:31:13,100 I'm going to use post for that instead. 649 00:31:13,100 --> 00:31:16,180 So the catch here is that this week, we now 650 00:31:16,180 --> 00:31:18,760 have the ability to implement slash register. 651 00:31:18,760 --> 00:31:22,480 Two weeks ago we could just send people to Google's slash search, 652 00:31:22,480 --> 00:31:25,120 but now we have the ability to make our own routes. 653 00:31:25,120 --> 00:31:29,780 But how many routes have we defined thus far in application.py? 654 00:31:29,780 --> 00:31:30,920 Just the one. 655 00:31:30,920 --> 00:31:34,610 And again, some new syntax with the funky at sign and the route 656 00:31:34,610 --> 00:31:35,690 keyword here. 657 00:31:35,690 --> 00:31:38,300 But let me actually just intuitively guess 658 00:31:38,300 --> 00:31:43,460 that if I go ahead and say app.route slash register, 659 00:31:43,460 --> 00:31:46,160 I bet I could implement a second route and tell the web server 660 00:31:46,160 --> 00:31:50,180 to listen in two places, on slash as well as on slash register. 661 00:31:50,180 --> 00:31:55,550 But if I wanted to listen specifically on post, it actually has to be this. 662 00:31:55,550 --> 00:31:58,670 Methods equals quote-unquote post. 663 00:31:58,670 --> 00:32:02,374 Because by default just for convenience, it assumes only gets. 664 00:32:02,374 --> 00:32:03,290 So I need to add that. 665 00:32:03,290 --> 00:32:05,124 You'd only know that from the documentation. 666 00:32:05,124 --> 00:32:07,123 Now I'm going to go ahead and define a function. 667 00:32:07,123 --> 00:32:09,050 This is slightly an annoying feature of Flask. 668 00:32:09,050 --> 00:32:11,716 You have to give the function a name even though you'll probably 669 00:32:11,716 --> 00:32:13,070 never reference it anywhere. 670 00:32:13,070 --> 00:32:15,980 So I'm going to go ahead and just reasonably call this register. 671 00:32:15,980 --> 00:32:18,060 And now I have a to do. 672 00:32:18,060 --> 00:32:23,066 What am I going to want to do when the user clicks that Submit button? 673 00:32:23,066 --> 00:32:23,858 AUDIENCE: Store it. 674 00:32:23,858 --> 00:32:25,607 DAVID MALAN: I want to store it somewhere. 675 00:32:25,607 --> 00:32:27,120 So I probably want to store it. 676 00:32:27,120 --> 00:32:30,560 But what might I want to do first before he or she is actually 677 00:32:30,560 --> 00:32:34,400 allowed to register, even though they've clicked that submit form? 678 00:32:34,400 --> 00:32:36,130 Maybe confirm their information, right? 679 00:32:36,130 --> 00:32:39,830 Because if a lazy user comes in, or if a user accidentally clicks the button 680 00:32:39,830 --> 00:32:42,771 or hits enter, they might actually submit nothing-- no name, no dorm. 681 00:32:42,771 --> 00:32:44,020 That's not useful information. 682 00:32:44,020 --> 00:32:45,687 It could just be perceived as spam. 683 00:32:45,687 --> 00:32:48,020 So we probably want to ask some kind of logical question 684 00:32:48,020 --> 00:32:51,130 like if they didn't give us a name or they didn't give us a dorm, 685 00:32:51,130 --> 00:32:53,149 yell at the user in some way. 686 00:32:53,149 --> 00:32:54,690 So I'm going to go ahead and do that. 687 00:32:54,690 --> 00:32:56,330 So let me actually express this in Python, 688 00:32:56,330 --> 00:32:58,640 kind of like we did last week with some error checking. 689 00:32:58,640 --> 00:33:03,680 So recall that the user's name can be gotten from an HTTP parameter. 690 00:33:03,680 --> 00:33:09,470 From the request.args get, and then ask for the name parameter. 691 00:33:09,470 --> 00:33:13,580 Their dorm, meanwhile, can come from request.args get dorm. 692 00:33:13,580 --> 00:33:16,520 And again, this request.args is something 693 00:33:16,520 --> 00:33:19,430 we gave ourselves access to up here when we said, hey Flask, 694 00:33:19,430 --> 00:33:22,790 please give me access to the user's request, that virtual envelope. 695 00:33:22,790 --> 00:33:26,390 Request.arg refers to all of the HTTP parameters in the URL. 696 00:33:26,390 --> 00:33:30,020 And get is just a function or a method built into that special Flask 697 00:33:30,020 --> 00:33:33,260 feature that allows us to get a specific parameter like name, 698 00:33:33,260 --> 00:33:35,180 or dorm, or anything else. 699 00:33:35,180 --> 00:33:38,390 And recall that in Python, what's kind of nice is that you can say pretty 700 00:33:38,390 --> 00:33:42,490 English-like, if not name or not-- 701 00:33:42,490 --> 00:33:46,170 not dorm, let's go ahead and reprimand the user. 702 00:33:46,170 --> 00:33:50,360 For instance, we could say failure because he or she did not actually 703 00:33:50,360 --> 00:33:51,980 cooperate as we intended. 704 00:33:51,980 --> 00:33:54,110 Otherwise if they did cooperate, I'm going 705 00:33:54,110 --> 00:33:58,070 to go ahead and render template success. 706 00:33:58,070 --> 00:34:00,030 And we'll flesh this out in just a moment. 707 00:34:00,030 --> 00:34:01,520 So I've got two scenarios handled. 708 00:34:01,520 --> 00:34:05,150 If they didn't cooperate or if they did, render quote-unquote failure 709 00:34:05,150 --> 00:34:07,320 or a full fledged HTML template. 710 00:34:07,320 --> 00:34:12,100 So now that I've implemented slash register and I'm listening for a route 711 00:34:12,100 --> 00:34:15,230 by a post, let's go ahead and reload the page for good measure. 712 00:34:15,230 --> 00:34:16,190 Type in my name. 713 00:34:16,190 --> 00:34:20,110 Not going to tell you my dorm, but you're going to notice as much. 714 00:34:20,110 --> 00:34:24,080 OK, so now the server has noticed that I didn't actually cooperate and provide 715 00:34:24,080 --> 00:34:25,250 both a name and a dorm. 716 00:34:25,250 --> 00:34:27,904 And so it's returning to me just quote-unquote failure. 717 00:34:27,904 --> 00:34:31,070 So that's good because now I know, all right, I did something wrong clearly. 718 00:34:31,070 --> 00:34:34,610 Let me go back let me go ahead and maybe do Canaday here. 719 00:34:34,610 --> 00:34:36,230 And now let me go ahead and register. 720 00:34:36,230 --> 00:34:39,230 But, but, but, but, this I know in advance is going to err. 721 00:34:39,230 --> 00:34:40,790 Why? 722 00:34:40,790 --> 00:34:42,290 I don't have a success.html. 723 00:34:42,290 --> 00:34:44,540 OK, so let's preemptively address this. 724 00:34:44,540 --> 00:34:47,239 Let me actually go in here to my templates directory. 725 00:34:47,239 --> 00:34:52,040 I'm going to go ahead and create a new file called success.html. 726 00:34:52,040 --> 00:34:54,399 Let me go into the templates to save it there. 727 00:34:54,399 --> 00:34:56,690 And you know what, success can be a pretty simple page. 728 00:34:56,690 --> 00:35:00,300 And let me open my index page, let me copy that, let me go into success, 729 00:35:00,300 --> 00:35:01,160 let me paste this. 730 00:35:01,160 --> 00:35:06,470 Let me get rid of all of that body and just say success, for instance. 731 00:35:06,470 --> 00:35:10,690 So let me now go ahead and go restart Flask, 732 00:35:10,690 --> 00:35:12,110 because I've made a new template. 733 00:35:12,110 --> 00:35:14,526 Let me go ahead and reload the form just for good measure. 734 00:35:14,526 --> 00:35:17,720 Let me go ahead and give you my name this time, and OK, I live in Canaday, 735 00:35:17,720 --> 00:35:19,760 and register. 736 00:35:19,760 --> 00:35:22,080 And what did I do wrong this time? 737 00:35:22,080 --> 00:35:25,940 So it turns out you can't do it this way, obviously. 738 00:35:25,940 --> 00:35:31,310 [LAUGHTER] So when you're actually submitting information to 739 00:35:31,310 --> 00:35:35,720 via a form via get, Flask very cleverly puts 740 00:35:35,720 --> 00:35:37,460 that information in a different place. 741 00:35:37,460 --> 00:35:40,370 Because by definition, as I claim very correctly earlier, 742 00:35:40,370 --> 00:35:42,860 in request.args are all of the key value pairs 743 00:35:42,860 --> 00:35:46,790 that are in the URL that are coming in from the user's request. 744 00:35:46,790 --> 00:35:50,870 But when you submit via post, for reasons I wish were now otherwise 745 00:35:50,870 --> 00:35:54,930 you actually have to access those values via a different variable. 746 00:35:54,930 --> 00:35:58,760 So instead of using request.args, you have to use request.form both here 747 00:35:58,760 --> 00:36:02,990 and here to make clear-- and this is horribly named for exactly the reasons 748 00:36:02,990 --> 00:36:04,550 that I think I'm tripping over here-- 749 00:36:04,550 --> 00:36:09,380 because they actually are both coming in via a form, via a get or post. 750 00:36:09,380 --> 00:36:15,770 But Flask puts get arguments in args and puts post arguments in form. 751 00:36:15,770 --> 00:36:18,020 Thereby leading clearly to potential confusion. 752 00:36:18,020 --> 00:36:24,920 But if I go ahead now and load this version of the site and I keep hoping, 753 00:36:24,920 --> 00:36:31,610 I'm going to go ahead now run Flask, restart this page, type in David, 754 00:36:31,610 --> 00:36:36,240 give you my dorm, and register and successfully register for froshim. 755 00:36:36,240 --> 00:36:39,020 See how easy web programming is? 756 00:36:39,020 --> 00:36:44,180 So hopefully now we can at least focus on the structure of what I've done 757 00:36:44,180 --> 00:36:45,590 and now begin to improve it. 758 00:36:45,590 --> 00:36:49,910 Because notice that I kind of did not practice what I preached a moment ago. 759 00:36:49,910 --> 00:36:56,054 What habit did I violate when I whipped up success.html? 760 00:36:56,054 --> 00:36:57,220 How did I get to that point? 761 00:36:57,220 --> 00:36:57,630 Yeah? 762 00:36:57,630 --> 00:36:57,960 AUDIENCE: Copy and paste. 763 00:36:57,960 --> 00:36:59,543 DAVID MALAN: Yeah, I copied and paste. 764 00:36:59,543 --> 00:37:02,450 Which again, usually in programming not the right thing to do. 765 00:37:02,450 --> 00:37:05,550 Might get the job done super fast, but it's probably the wrong instinct, 766 00:37:05,550 --> 00:37:07,170 because it's going to get harder and harder to maintain. 767 00:37:07,170 --> 00:37:08,060 Now, why is that? 768 00:37:08,060 --> 00:37:10,220 You've played HTML a couple of weeks ago. 769 00:37:10,220 --> 00:37:13,940 And recall from that problem set when you had to make a home page, 770 00:37:13,940 --> 00:37:17,540 you probably found yourselves copying and pasting across your two, 771 00:37:17,540 --> 00:37:20,930 or three, or four pages because you wanted them to kind of look the same. 772 00:37:20,930 --> 00:37:23,720 And therefore it made sense for them to have some commonalities. 773 00:37:23,720 --> 00:37:28,730 But in HTML alone, there was no way to say use the same layout for my whole 774 00:37:28,730 --> 00:37:32,060 site-- use the same color scheme, the same fonts, the same CSS-- 775 00:37:32,060 --> 00:37:35,511 but just change the body of the page for each individual page. 776 00:37:35,511 --> 00:37:38,010 And so some of you very rightly on discourse and beyond like 777 00:37:38,010 --> 00:37:39,880 posted questions asking, could you do this? 778 00:37:39,880 --> 00:37:43,030 And you can't really in HTML alone. 779 00:37:43,030 --> 00:37:46,050 But now that we have access to Python, an actual programming language 780 00:37:46,050 --> 00:37:48,330 they can do things logically, now you can actually 781 00:37:48,330 --> 00:37:50,490 start to factor those things out, too. 782 00:37:50,490 --> 00:37:57,000 And notice in this file, success.html, as well as in index.html, 783 00:37:57,000 --> 00:38:00,120 what are some of the commonalities, suffice it to say? 784 00:38:00,120 --> 00:38:02,520 The form is only in one of them, but what 785 00:38:02,520 --> 00:38:06,190 else is obviously redundant everywhere? 786 00:38:06,190 --> 00:38:10,840 The title, the head of the page more generally, the doctype at the very top, 787 00:38:10,840 --> 00:38:11,767 the body tag alone. 788 00:38:11,767 --> 00:38:14,850 And you could imagine there'd be even more details like from your own home 789 00:38:14,850 --> 00:38:18,350 pages that you wanted to be the same across multiple pages. 790 00:38:18,350 --> 00:38:22,120 So let's actually take a look at a refactorization of this code, 791 00:38:22,120 --> 00:38:25,090 the one I did write in advance in froshim0, 792 00:38:25,090 --> 00:38:28,030 and you'll see why it actually makes sense 793 00:38:28,030 --> 00:38:30,820 to have not only multiple files, each of which 794 00:38:30,820 --> 00:38:34,060 represents one of your routes or your views, 795 00:38:34,060 --> 00:38:37,720 but also to have this file called layout.html. 796 00:38:37,720 --> 00:38:40,570 In Flask, when building a web application that you know 797 00:38:40,570 --> 00:38:43,570 is going to follow a certain structural pattern, commonalities 798 00:38:43,570 --> 00:38:46,790 across all of your pages, you can actually do this. 799 00:38:46,790 --> 00:38:52,570 So in this file here, layout.html is a whole bunch of hardcoded HTML. 800 00:38:52,570 --> 00:38:53,540 And it's pretty simple. 801 00:38:53,540 --> 00:38:57,830 It's got my HTML tag, head tag, title tag, body tag, and a few other things, 802 00:38:57,830 --> 00:38:59,870 but that's the general structure of the page. 803 00:38:59,870 --> 00:39:02,290 And notice it has this funky syntax in the middle. 804 00:39:02,290 --> 00:39:04,960 In white here is what's called the block. 805 00:39:04,960 --> 00:39:07,010 This is now Flask specific. 806 00:39:07,010 --> 00:39:09,760 Just like Flask supports those two curly braces on the left 807 00:39:09,760 --> 00:39:12,520 and the right that says put a value here, flask 808 00:39:12,520 --> 00:39:17,230 also supports this other notation, curly brace percent and percent curly 809 00:39:17,230 --> 00:39:22,900 brace that actually allows you to put placeholders for actual chunks of HTML. 810 00:39:22,900 --> 00:39:26,050 Not just variables, but actual chunks of HTML. 811 00:39:26,050 --> 00:39:29,470 And so this layout you can think of as a mold or a template 812 00:39:29,470 --> 00:39:33,780 literally that all of your other pages are going to be structured based on, 813 00:39:33,780 --> 00:39:37,180 but they are going to vary in this line and only this line. 814 00:39:37,180 --> 00:39:40,600 And we're going to put as much HTML between the body tags as we want, 815 00:39:40,600 --> 00:39:42,070 the open and the close tag. 816 00:39:42,070 --> 00:39:45,860 This just indicates to Flask this is the stuff that should be changing. 817 00:39:45,860 --> 00:39:50,070 So if I now look at my index.html, which recall earlier 818 00:39:50,070 --> 00:39:53,260 contained my form index.html. 819 00:39:53,260 --> 00:39:55,782 Notice that here's the form, and I finished it earlier. 820 00:39:55,782 --> 00:39:57,990 I went ahead and typed out all of the freshman dorms, 821 00:39:57,990 --> 00:39:59,260 not just the two of them. 822 00:39:59,260 --> 00:40:01,840 And you'll see that the file starts almost the same 823 00:40:01,840 --> 00:40:03,980 and then continues with more stuff. 824 00:40:03,980 --> 00:40:07,090 But notice what's missing from index.html this time. 825 00:40:07,090 --> 00:40:08,350 No doctype. 826 00:40:08,350 --> 00:40:09,820 No HTML tag. 827 00:40:09,820 --> 00:40:12,340 No head tag, no title tag, no body tag. 828 00:40:12,340 --> 00:40:14,770 All of the common stuff has been factored out. 829 00:40:14,770 --> 00:40:18,280 But there's some funky new syntax that, again, is Flask specific. 830 00:40:18,280 --> 00:40:22,090 This first line is the link between this file and the layout. 831 00:40:22,090 --> 00:40:25,870 That first line says, hey Flask, this index.html file 832 00:40:25,870 --> 00:40:29,140 extends the definition of layout.html. 833 00:40:29,140 --> 00:40:31,660 So it says grab that template and plug myself in there. 834 00:40:31,660 --> 00:40:32,920 What do you want to plug in? 835 00:40:32,920 --> 00:40:34,300 The same syntax here. 836 00:40:34,300 --> 00:40:37,570 When you actually put stuff between the block tag 837 00:40:37,570 --> 00:40:42,130 and the end block tag, which is down below, that's when you say to Flask, 838 00:40:42,130 --> 00:40:46,540 go ahead and take this stuff and plug it into the placeholder in the layout. 839 00:40:46,540 --> 00:40:51,130 So meanwhile, the success page also now can be a little more sophisticated. 840 00:40:51,130 --> 00:40:54,070 If I go into success, it's not very complicated. 841 00:40:54,070 --> 00:40:55,960 And honestly, it doesn't even look like HTML 842 00:40:55,960 --> 00:40:58,600 anymore because we're using these more dynamic features. 843 00:40:58,600 --> 00:41:01,180 But this just says, hey Flask, use the same layout 844 00:41:01,180 --> 00:41:03,410 so the page is structured exactly the same. 845 00:41:03,410 --> 00:41:07,420 But for the body, go ahead and plug in this value instead. 846 00:41:07,420 --> 00:41:10,225 So indeed, when you go ahead and load this success message, 847 00:41:10,225 --> 00:41:12,100 you see this message here-- not just success, 848 00:41:12,100 --> 00:41:14,226 I expounded here and said you are registered. 849 00:41:14,226 --> 00:41:16,600 Well, not really, that's because there's no database yet. 850 00:41:16,600 --> 00:41:19,240 But that's going to generate a full fledged HTML page. 851 00:41:19,240 --> 00:41:20,290 And what about failure? 852 00:41:20,290 --> 00:41:22,810 Before I was just cheating and just saying return failure, 853 00:41:22,810 --> 00:41:24,640 quote-unquote, no HTML at all. 854 00:41:24,640 --> 00:41:27,100 The failure page is going to be almost the same, 855 00:41:27,100 --> 00:41:30,220 but now I can actually provide some descriptive text. 856 00:41:30,220 --> 00:41:33,400 This body just says you must provide your name and dorm, 857 00:41:33,400 --> 00:41:37,040 thereby admonishing the user for not having cooperated properly. 858 00:41:37,040 --> 00:41:40,120 So now your home pages, if you kind of extrapolate from this, 859 00:41:40,120 --> 00:41:43,630 could have the exact same layout, aesthetics and menu bars, 860 00:41:43,630 --> 00:41:46,764 and all of that fanciness, but only the content would have to change. 861 00:41:46,764 --> 00:41:49,430 And you can get out of the business of just copying and pasting. 862 00:41:49,430 --> 00:41:51,970 So there, too, to your question earlier about dynamism, 863 00:41:51,970 --> 00:41:54,420 the dynamism doesn't have to just come from the user. 864 00:41:54,420 --> 00:41:58,180 It can also come from the construction dynamically of a website 865 00:41:58,180 --> 00:41:59,202 based on multiple pages. 866 00:41:59,202 --> 00:42:00,910 So at the end of the day, the browser has 867 00:42:00,910 --> 00:42:05,560 no idea that Python exists, has no familiarity with Flask. 868 00:42:05,560 --> 00:42:08,020 All the browser still sees is an HTML page. 869 00:42:08,020 --> 00:42:10,030 But what Flask and in turn Python are doing 870 00:42:10,030 --> 00:42:13,630 for us is constructing that page dynamically, following 871 00:42:13,630 --> 00:42:15,850 the rules from two weeks to go in HTML and CSS, 872 00:42:15,850 --> 00:42:19,654 and following last week's rules on how Python works. 873 00:42:19,654 --> 00:42:22,606 Questions? 874 00:42:22,606 --> 00:42:25,558 AUDIENCE: So even though [INAUDIBLE] 875 00:42:25,558 --> 00:42:33,930 876 00:42:33,930 --> 00:42:35,070 DAVID MALAN: It's not. 877 00:42:35,070 --> 00:42:36,180 Good question. 878 00:42:36,180 --> 00:42:39,300 This new syntax, the double curly braces that we saw earlier and now 879 00:42:39,300 --> 00:42:43,410 the curly brace percent signs, this is actually yet another language 880 00:42:43,410 --> 00:42:44,420 called jinja-- 881 00:42:44,420 --> 00:42:48,617 J-I-N-J-A-- which is a templating language. 882 00:42:48,617 --> 00:42:51,450 And there's dozens of these things in the world, people just come up 883 00:42:51,450 --> 00:42:52,740 with their own syntax. 884 00:42:52,740 --> 00:42:56,370 And the reason for the funky syntax is that the author of jinja 885 00:42:56,370 --> 00:42:58,920 presumably could think of no other language that 886 00:42:58,920 --> 00:43:01,530 uses like a curly brace and a percent sign 887 00:43:01,530 --> 00:43:03,156 and a percent sign and a curly brace. 888 00:43:03,156 --> 00:43:05,030 And so therefore they decided, you know what, 889 00:43:05,030 --> 00:43:08,370 I'm going to use this syntax because it will look distinct from HTML, 890 00:43:08,370 --> 00:43:11,970 and CSS, and Python So that frameworks like Flask 891 00:43:11,970 --> 00:43:14,397 don't confuse it with something else. 892 00:43:14,397 --> 00:43:18,370 AUDIENCE: So do you have to upload that into [INAUDIBLE],, or is it automatic? 893 00:43:18,370 --> 00:43:20,120 DAVID MALAN: It's automatically supported. 894 00:43:20,120 --> 00:43:23,550 So Flask by default supports jinja. 895 00:43:23,550 --> 00:43:25,890 It could have come up with its own templating syntax. 896 00:43:25,890 --> 00:43:29,182 But whoever invented Flask decided I don't need to reinvent this wheel, 897 00:43:29,182 --> 00:43:31,140 someone else already made a templating language 898 00:43:31,140 --> 00:43:32,640 that gives me this functionality. 899 00:43:32,640 --> 00:43:34,785 So I'm going to combine our works into one. 900 00:43:34,785 --> 00:43:36,660 And I didn't call it a language a moment ago, 901 00:43:36,660 --> 00:43:39,257 because frankly, HTML, CSS, Python, JavaScript-- 902 00:43:39,257 --> 00:43:41,340 I mean, we're already running out of fingers here. 903 00:43:41,340 --> 00:43:43,810 But jinja is, indeed, yet another language. 904 00:43:43,810 --> 00:43:46,050 It's just not a programming language per se, 905 00:43:46,050 --> 00:43:48,180 though it will have some control flow features 906 00:43:48,180 --> 00:43:49,471 that we'll see in a little bit. 907 00:43:49,471 --> 00:43:51,150 It's just much more limited than Python. 908 00:43:51,150 --> 00:43:52,100 Other questions? 909 00:43:52,100 --> 00:43:54,780 AUDIENCE: Is it possible to combine the success and failure HTML 910 00:43:54,780 --> 00:43:57,495 files into one just for better design? 911 00:43:57,495 --> 00:43:58,620 DAVID MALAN: Good question. 912 00:43:58,620 --> 00:44:03,180 Could you combine the success and the failure pages into one? 913 00:44:03,180 --> 00:44:04,110 Short answer, yes. 914 00:44:04,110 --> 00:44:07,110 And let me not show it yet, because it'll get a little more complicated. 915 00:44:07,110 --> 00:44:11,370 But yes, I could imagine passing a variable in that's a Boolean-- 916 00:44:11,370 --> 00:44:12,420 true or false-- 917 00:44:12,420 --> 00:44:13,800 into just one of these templates. 918 00:44:13,800 --> 00:44:17,190 And maybe I call the new template result.html. 919 00:44:17,190 --> 00:44:20,700 I can actually then have an if condition in my template that 920 00:44:20,700 --> 00:44:23,100 says if the result is true, say this. 921 00:44:23,100 --> 00:44:25,510 Else if the result is false, say this other thing. 922 00:44:25,510 --> 00:44:27,030 So you could do that, yes. 923 00:44:27,030 --> 00:44:31,045 Generally, though, it's probably cleaner to keep messaging separate 924 00:44:31,045 --> 00:44:32,670 if they functionally do something else. 925 00:44:32,670 --> 00:44:35,430 After all, these files are pretty small anyway. 926 00:44:35,430 --> 00:44:36,112 Yeah? 927 00:44:36,112 --> 00:44:38,070 AUDIENCE: Just for question, what does the user 928 00:44:38,070 --> 00:44:42,000 see if they were to open up the debugging console on Chrome 929 00:44:42,000 --> 00:44:46,474 and look at at it, what do they see as the HTML that shows up? 930 00:44:46,474 --> 00:44:47,890 DAVID MALAN: Really good question. 931 00:44:47,890 --> 00:44:48,848 What does the user see? 932 00:44:48,848 --> 00:44:51,870 We can answer this by just literally opening Chrome and opening 933 00:44:51,870 --> 00:44:53,970 View Page Source or the Inspector. 934 00:44:53,970 --> 00:44:55,290 This is what the browser sees. 935 00:44:55,290 --> 00:44:58,770 So when I claimed earlier that the browser has no idea of Python or Flask 936 00:44:58,770 --> 00:45:00,720 are even involved, that is, indeed, true. 937 00:45:00,720 --> 00:45:02,970 Because what browser's receiving at the end of the day 938 00:45:02,970 --> 00:45:06,397 is just this, the dynamically constructed HTML. 939 00:45:06,397 --> 00:45:06,980 Good question. 940 00:45:06,980 --> 00:45:07,774 Yeah? 941 00:45:07,774 --> 00:45:11,092 AUDIENCE: [INAUDIBLE] can you also put Python code in there, 942 00:45:11,092 --> 00:45:11,997 or is it just HTML? 943 00:45:11,997 --> 00:45:12,580 Good question. 944 00:45:12,580 --> 00:45:14,413 We'll see more of this in just a little bit. 945 00:45:14,413 --> 00:45:17,840 The question is, can you between the curly brace and percent signs 946 00:45:17,840 --> 00:45:19,630 put actual Python code? 947 00:45:19,630 --> 00:45:23,170 You can put stuff that looks like Python code, but not all of Python. 948 00:45:23,170 --> 00:45:24,715 And so more of that in a bit. 949 00:45:24,715 --> 00:45:26,200 AUDIENCE: Is there a function call or something like that? 950 00:45:26,200 --> 00:45:27,700 DAVID MALAN: Only certain functions. 951 00:45:27,700 --> 00:45:30,310 Templating languages, long story short, are sandbox so 952 00:45:30,310 --> 00:45:33,310 that they are not as expressive as a real programming language. 953 00:45:33,310 --> 00:45:36,115 Otherwise you are vulnerable to potential hacks. 954 00:45:36,115 --> 00:45:38,740 You want their functionality to be very limited because they're 955 00:45:38,740 --> 00:45:42,820 only about displaying data, not about thinking or doing logic generally. 956 00:45:42,820 --> 00:45:43,787 More on that in a bit. 957 00:45:43,787 --> 00:45:45,370 All right, that was a lot all at once. 958 00:45:45,370 --> 00:45:48,161 Let's take a five minute break here, turn on some music, come back, 959 00:45:48,161 --> 00:45:49,771 and we'll make this act better. 960 00:45:49,771 --> 00:45:51,310 All right, we are back. 961 00:45:51,310 --> 00:45:54,820 So to recap where froshim0 left off, we now 962 00:45:54,820 --> 00:45:58,120 have this structure which is pretty much conventional. 963 00:45:58,120 --> 00:46:00,640 Any web application we make here on out is 964 00:46:00,640 --> 00:46:04,540 going to follow this pattern of having an application.py entry point where 965 00:46:04,540 --> 00:46:08,112 all the interesting stuff starts, a layout.html file 966 00:46:08,112 --> 00:46:09,820 in your templates directory that lays out 967 00:46:09,820 --> 00:46:13,900 the whole site and any commonalities, and then one or more other pages that 968 00:46:13,900 --> 00:46:17,440 actually represent your individual views that correspond to one or more 969 00:46:17,440 --> 00:46:18,760 of your actual routes. 970 00:46:18,760 --> 00:46:21,430 So now we're at the point of a stable baseline, 971 00:46:21,430 --> 00:46:25,000 but had we dived in right to this, it would perhaps not make as much sense 972 00:46:25,000 --> 00:46:27,920 as to why we did this various factorization. 973 00:46:27,920 --> 00:46:29,260 So let's now improve this. 974 00:46:29,260 --> 00:46:31,930 Because of course, if you look at success.html, 975 00:46:31,930 --> 00:46:33,410 it just claims you are registered. 976 00:46:33,410 --> 00:46:34,580 Well, not really. 977 00:46:34,580 --> 00:46:40,730 Because in application.py, did we do anything with the user's information? 978 00:46:40,730 --> 00:46:41,230 No. 979 00:46:41,230 --> 00:46:43,146 We just checked, did they give us information? 980 00:46:43,146 --> 00:46:44,560 And if so, we claim success. 981 00:46:44,560 --> 00:46:48,040 Else if they missed their name and/or their dorm, we just claimed failure. 982 00:46:48,040 --> 00:46:51,550 So what might a data structure be in Python 983 00:46:51,550 --> 00:46:53,026 where we could store registrants? 984 00:46:53,026 --> 00:46:55,150 We don't have databases yet, we don't have SQL yet. 985 00:46:55,150 --> 00:46:56,340 That's a week ahead. 986 00:46:56,340 --> 00:46:57,040 AUDIENCE: Array. 987 00:46:57,040 --> 00:46:59,415 DAVID MALAN: Yeah, we could use an array, otherwise known 988 00:46:59,415 --> 00:47:00,430 as a list in Python. 989 00:47:00,430 --> 00:47:02,500 So let me propose how we might do this. 990 00:47:02,500 --> 00:47:08,050 Let me actually open up froshims1 for our second iteration of this program. 991 00:47:08,050 --> 00:47:10,510 And in application.py, notice this. 992 00:47:10,510 --> 00:47:12,970 At the very top of the file, not only am I 993 00:47:12,970 --> 00:47:16,390 creating my application using the same line as before, 994 00:47:16,390 --> 00:47:19,990 and I've commented things this time in advance using the hash symbol, 995 00:47:19,990 --> 00:47:22,660 notice that I claim that on line 6 and 7 here, here 996 00:47:22,660 --> 00:47:25,540 is an empty list for all of the students who have registered. 997 00:47:25,540 --> 00:47:27,479 This way we can keep the information around. 998 00:47:27,479 --> 00:47:29,770 And we only did this briefly last time, but does anyone 999 00:47:29,770 --> 00:47:33,330 remember how you add something to a list in Python? 1000 00:47:33,330 --> 00:47:35,100 By what function? 1001 00:47:35,100 --> 00:47:36,030 Append. 1002 00:47:36,030 --> 00:47:38,594 So if you have .append at the end of a list's name, 1003 00:47:38,594 --> 00:47:39,760 you can add something to it. 1004 00:47:39,760 --> 00:47:41,110 So where is that going to go? 1005 00:47:41,110 --> 00:47:44,841 Well, here is my route for slash, implies, again, get by default. 1006 00:47:44,841 --> 00:47:46,840 That's the default route that a human might get, 1007 00:47:46,840 --> 00:47:50,470 and they are going to see index.html, which contains that form. 1008 00:47:50,470 --> 00:47:55,270 If I scroll down now, you'll see that I have a register route just like before. 1009 00:47:55,270 --> 00:47:58,330 But I'm doing one additional step. 1010 00:47:58,330 --> 00:48:01,432 Which is the new line here, to be clear? 1011 00:48:01,432 --> 00:48:03,100 Yeah, 26. 1012 00:48:03,100 --> 00:48:05,420 So I could implement this in any number of ways. 1013 00:48:05,420 --> 00:48:08,120 But the key detail is that I reference the list name-- students, 1014 00:48:08,120 --> 00:48:09,620 but I could have called it anything. 1015 00:48:09,620 --> 00:48:12,870 .append, as someone proposed, is how you add something to the end of the list. 1016 00:48:12,870 --> 00:48:14,328 And then I can add anything I want. 1017 00:48:14,328 --> 00:48:16,514 To keep it simple, I'm just going to add a string. 1018 00:48:16,514 --> 00:48:18,430 And I'm going to keep it super simple and just 1019 00:48:18,430 --> 00:48:21,940 say the string is so-and-so from such and such a dorm. 1020 00:48:21,940 --> 00:48:25,480 So David from Matthews Hall, or Brian from wherever. 1021 00:48:25,480 --> 00:48:28,771 And so here we have placeholders using f strings in Python. 1022 00:48:28,771 --> 00:48:30,520 So this has nothing to do with Flask, this 1023 00:48:30,520 --> 00:48:33,550 has nothing to do with jinja or anything we just talked about. 1024 00:48:33,550 --> 00:48:37,450 This has to do everything with last week's syntax in Python alone. 1025 00:48:37,450 --> 00:48:42,050 So this appends to that list this name from this dorm. 1026 00:48:42,050 --> 00:48:44,830 So let's go ahead now and try this version out. 1027 00:48:44,830 --> 00:48:50,200 If I go into my source sub and directory for today's code into froshims1 1028 00:48:50,200 --> 00:48:54,010 and run flask run, we'll see a URL that I can now visit. 1029 00:48:54,010 --> 00:48:56,630 Let me go ahead and open that for froshims1. 1030 00:48:56,630 --> 00:48:59,140 Notice that I have that complete dropdown now. 1031 00:48:59,140 --> 00:49:02,890 Let me go ahead and say David, but I'm not going to tell you my dorm 1032 00:49:02,890 --> 00:49:04,720 yet and try to register. 1033 00:49:04,720 --> 00:49:07,210 Now I see a more friendly message, not just failure. 1034 00:49:07,210 --> 00:49:10,030 And that's because of my new and improved template. 1035 00:49:10,030 --> 00:49:12,670 OK, I'll go ahead and be David, and I'll be from Matthews here. 1036 00:49:12,670 --> 00:49:14,800 Let me go ahead and register and voila. 1037 00:49:14,800 --> 00:49:17,344 Now we see David from Matthews has registered. 1038 00:49:17,344 --> 00:49:20,260 And it seems to be all of a sudden in the form of a new bulleted list. 1039 00:49:20,260 --> 00:49:22,129 But where did that actually come from? 1040 00:49:22,129 --> 00:49:22,920 Well, I don't know. 1041 00:49:22,920 --> 00:49:23,836 Let me try this again. 1042 00:49:23,836 --> 00:49:26,860 Let me go back to slash, which is the route that gives me the form. 1043 00:49:26,860 --> 00:49:29,765 Let me go ahead and type in not David this time, but say, Brian. 1044 00:49:29,765 --> 00:49:31,140 And Brian, which dorm are you in? 1045 00:49:31,140 --> 00:49:32,080 AUDIENCE: Pennypacker. 1046 00:49:32,080 --> 00:49:33,121 DAVID MALAN: Pennypacker. 1047 00:49:33,121 --> 00:49:36,070 So let me choose this from the menu instead and click Register. 1048 00:49:36,070 --> 00:49:37,690 And now we see Brian from Pennypacker. 1049 00:49:37,690 --> 00:49:39,970 So somehow the application is changing state, 1050 00:49:39,970 --> 00:49:43,730 and notice the URL that we're at is called slash registrants. 1051 00:49:43,730 --> 00:49:47,530 So that seems to be a third route this time that apparently is not interactive 1052 00:49:47,530 --> 00:49:50,480 per se, it just spits out the list of registered students. 1053 00:49:50,480 --> 00:49:53,470 So let's just put the proverbial engineering hat on. 1054 00:49:53,470 --> 00:49:56,950 If we go about implementing this slash registrants route, 1055 00:49:56,950 --> 00:50:03,976 logically what must that code be doing in verbal pseudocode, if you will? 1056 00:50:03,976 --> 00:50:05,310 AUDIENCE: A for loop? 1057 00:50:05,310 --> 00:50:07,600 DAVID MALAN: Like a for loop, iterating over what? 1058 00:50:07,600 --> 00:50:10,170 AUDIENCE: In the list that saves all the registrants. 1059 00:50:10,170 --> 00:50:11,100 DAVID MALAN: Yeah. 1060 00:50:11,100 --> 00:50:13,140 Iterating over the list of students which 1061 00:50:13,140 --> 00:50:14,640 contains all of those registrants. 1062 00:50:14,640 --> 00:50:18,990 And the template, meanwhile, probably has like an LI tag for list item 1063 00:50:18,990 --> 00:50:22,480 and a UL tag for unordered list, which gives me the bulleted list. 1064 00:50:22,480 --> 00:50:23,740 So let's take a look at that. 1065 00:50:23,740 --> 00:50:25,990 So how do we follow these breadcrumbs? 1066 00:50:25,990 --> 00:50:29,310 Well, if I scroll up in application.py, we'll 1067 00:50:29,310 --> 00:50:31,440 see a route called slash registrants. 1068 00:50:31,440 --> 00:50:33,840 And you'll see that all it does apparently 1069 00:50:33,840 --> 00:50:36,860 is it returns a template called registered.html, 1070 00:50:36,860 --> 00:50:40,320 where registered.html is probably a template that is generating that list. 1071 00:50:40,320 --> 00:50:42,900 But there's something different this time. 1072 00:50:42,900 --> 00:50:44,160 I'm passing in an argument. 1073 00:50:44,160 --> 00:50:45,390 And we saw this earlier. 1074 00:50:45,390 --> 00:50:48,720 When I wanted to pass in name equals David or name equals Brian, 1075 00:50:48,720 --> 00:50:51,450 I just grabbed that from a variable. 1076 00:50:51,450 --> 00:50:54,564 This time I'm not doing request.args, I'm not doing request.form. 1077 00:50:54,564 --> 00:50:55,605 Because what is students? 1078 00:50:55,605 --> 00:50:58,400 1079 00:50:58,400 --> 00:51:00,750 Where did this come from? 1080 00:51:00,750 --> 00:51:02,510 That's the list from higher up. 1081 00:51:02,510 --> 00:51:06,470 Recall that we have this global variable at the top of the program, students, 1082 00:51:06,470 --> 00:51:08,240 which is initialized to an empty list. 1083 00:51:08,240 --> 00:51:11,990 But recall that we keep appending to it in my register route. 1084 00:51:11,990 --> 00:51:13,850 So I can go ahead and say, you know what? 1085 00:51:13,850 --> 00:51:18,020 Go ahead and pass into register.html a template-- or rather, a list-- 1086 00:51:18,020 --> 00:51:21,284 called students whose value is exactly that. 1087 00:51:21,284 --> 00:51:24,200 And again, it's stupid looking that you have the same word on the left 1088 00:51:24,200 --> 00:51:26,121 and the right of the variable name. 1089 00:51:26,121 --> 00:51:27,370 You could do this differently. 1090 00:51:27,370 --> 00:51:30,290 Again, you could say foo, you could say x, or y, or anything. 1091 00:51:30,290 --> 00:51:32,670 But frankly, it tends to make most sense, just pass 1092 00:51:32,670 --> 00:51:36,230 in the same name as the variable that you care about so that the template can 1093 00:51:36,230 --> 00:51:37,320 see exactly that. 1094 00:51:37,320 --> 00:51:38,570 So what's the next breadcrumb? 1095 00:51:38,570 --> 00:51:40,653 If I want to understand exactly what is happening, 1096 00:51:40,653 --> 00:51:43,600 what file should I open up next perhaps? 1097 00:51:43,600 --> 00:51:44,970 Probably register.html. 1098 00:51:44,970 --> 00:51:46,150 So let's go in there. 1099 00:51:46,150 --> 00:51:48,260 It's in my templates directory by definition, 1100 00:51:48,260 --> 00:51:51,850 and you'll see, indeed, a failure message which allows me to error check. 1101 00:51:51,850 --> 00:51:55,700 Index, which contains the form; layout, which contains the overall structure; 1102 00:51:55,700 --> 00:51:58,390 and finally, registered.html. 1103 00:51:58,390 --> 00:52:01,960 And now we can answer the question that you asked earlier about Python code 1104 00:52:01,960 --> 00:52:03,020 in the template. 1105 00:52:03,020 --> 00:52:05,660 So this one looks more advanced than before, 1106 00:52:05,660 --> 00:52:07,760 but notice it follows a pattern. 1107 00:52:07,760 --> 00:52:10,360 Register.html extends that same layout. 1108 00:52:10,360 --> 00:52:13,120 So it borrows from that same mold, so it looks the same. 1109 00:52:13,120 --> 00:52:16,570 The body of this page, though, is just this snippet of HTML. 1110 00:52:16,570 --> 00:52:19,390 Give me an unordered list, open and closed, and this 1111 00:52:19,390 --> 00:52:21,040 is what you can do now with jinja. 1112 00:52:21,040 --> 00:52:23,260 Again, it's almost identical to Python, so you 1113 00:52:23,260 --> 00:52:26,360 don't have to worry about thinking about learning yet another language. 1114 00:52:26,360 --> 00:52:28,820 It's just a subset of Python essentially. 1115 00:52:28,820 --> 00:52:33,370 So if I want to output in the list of all of the students, 1116 00:52:33,370 --> 00:52:37,262 I use my jinja syntax here, my template syntax with curly brace percent. 1117 00:52:37,262 --> 00:52:38,720 And I say for student and students. 1118 00:52:38,720 --> 00:52:42,344 Just like in Python, that induces an iteration over that list. 1119 00:52:42,344 --> 00:52:43,760 And then what do I want to output? 1120 00:52:43,760 --> 00:52:46,810 Well, we can borrow our curly braces from our name example 1121 00:52:46,810 --> 00:52:51,460 and just do list item, plug in the name of the student, close list item. 1122 00:52:51,460 --> 00:52:53,080 And then endfor. 1123 00:52:53,080 --> 00:52:55,240 So this is the one stupid thing with the templates. 1124 00:52:55,240 --> 00:52:58,360 Whereas in Python proper, recall that you can just 1125 00:52:58,360 --> 00:53:00,550 say for student in students, you have a colon 1126 00:53:00,550 --> 00:53:02,740 and then indentation handles everything. 1127 00:53:02,740 --> 00:53:04,720 The problem with that in the world of HTML 1128 00:53:04,720 --> 00:53:07,660 is that browsers recall ignore all whitespace, 1129 00:53:07,660 --> 00:53:10,750 like whitespace has no special significance, but in Python it does. 1130 00:53:10,750 --> 00:53:14,020 So the way people solve this is you literally, 1131 00:53:14,020 --> 00:53:16,090 if a little weirdly, say endfor-- 1132 00:53:16,090 --> 00:53:17,817 one word, no space. 1133 00:53:17,817 --> 00:53:18,400 And that's it. 1134 00:53:18,400 --> 00:53:20,800 And indentation helps you read something like this. 1135 00:53:20,800 --> 00:53:22,694 So what is the HTML I'm getting back? 1136 00:53:22,694 --> 00:53:23,860 I can actually look at this. 1137 00:53:23,860 --> 00:53:26,200 Let me go ahead and view page source in Chrome, 1138 00:53:26,200 --> 00:53:28,577 and you'll see it's not quite as pretty as might be ideal 1139 00:53:28,577 --> 00:53:31,410 because there's a lot of whitespace which comes from those templates 1140 00:53:31,410 --> 00:53:33,340 from my having pretty printed those, as well. 1141 00:53:33,340 --> 00:53:36,490 But this is syntactically correct, and I'm dynamically putting 1142 00:53:36,490 --> 00:53:40,120 this part inside of this layout. 1143 00:53:40,120 --> 00:53:42,742 Any questions, then, on this? 1144 00:53:42,742 --> 00:53:47,220 AUDIENCE: So if we restart the server, whatever's stored 1145 00:53:47,220 --> 00:53:49,180 in the list, that goes away, right? 1146 00:53:49,180 --> 00:53:50,305 DAVID MALAN: Good question. 1147 00:53:50,305 --> 00:53:51,940 Let's kill Flask with control-c. 1148 00:53:51,940 --> 00:53:53,590 Let's rerun the server. 1149 00:53:53,590 --> 00:53:57,640 And let me go back to my registrants route and reload. 1150 00:53:57,640 --> 00:54:01,090 And sadly, yes, this is not the best way to register students for a sport. 1151 00:54:01,090 --> 00:54:04,570 Because if the server ever goes offline, loses power, you hit control-c, 1152 00:54:04,570 --> 00:54:06,670 you obviously, indeed, lose everyone. 1153 00:54:06,670 --> 00:54:08,620 And notice, too, even though we've generally 1154 00:54:08,620 --> 00:54:12,850 frowned upon using global variables, which this students list indeed 1155 00:54:12,850 --> 00:54:17,170 is, why did I define it up here in line 7 and not, 1156 00:54:17,170 --> 00:54:20,430 for instance, in my register route here? 1157 00:54:20,430 --> 00:54:23,320 Because indeed, I'm appending to the list here. 1158 00:54:23,320 --> 00:54:28,900 But I very deliberately did not declare the list there. 1159 00:54:28,900 --> 00:54:29,635 Yeah? 1160 00:54:29,635 --> 00:54:31,530 AUDIENCE: You're using it in other parts. 1161 00:54:31,530 --> 00:54:34,780 DAVID MALAN: I'm using it elsewhere in my other routes, the registrants route. 1162 00:54:34,780 --> 00:54:38,180 And also even more to the point, if I declared a list here, 1163 00:54:38,180 --> 00:54:40,039 it becomes by definition a local variable. 1164 00:54:40,039 --> 00:54:41,830 Which means as soon as this function exits, 1165 00:54:41,830 --> 00:54:45,760 now I've just thrown away those students who register immediately not 1166 00:54:45,760 --> 00:54:47,344 even after a control-c. 1167 00:54:47,344 --> 00:54:49,510 So this was a better approach to do it, but it's not 1168 00:54:49,510 --> 00:54:51,850 what I did way back in my day. 1169 00:54:51,850 --> 00:54:54,130 I actually did something that was a little fancier. 1170 00:54:54,130 --> 00:54:56,350 So at the time, I didn't really know-- at least in, 1171 00:54:56,350 --> 00:54:58,496 what, 1997-- anything about databases. 1172 00:54:58,496 --> 00:55:01,120 I don't think I even knew about CSV files just yet, or at least 1173 00:55:01,120 --> 00:55:02,920 how to create them dynamically. 1174 00:55:02,920 --> 00:55:05,110 So I instead took this approach. 1175 00:55:05,110 --> 00:55:11,320 Let me go into froshims2, and it has noticed the same templates as before. 1176 00:55:11,320 --> 00:55:14,410 And indeed, I pretty much copied and pasted for this second example. 1177 00:55:14,410 --> 00:55:17,980 But in application.py, notice this fanciness. 1178 00:55:17,980 --> 00:55:22,300 So here I have almost the same thing up top in terms of Flask, 1179 00:55:22,300 --> 00:55:25,670 but I'm also using this OS library, more on that in a bit. 1180 00:55:25,670 --> 00:55:27,460 But what about line 2? 1181 00:55:27,460 --> 00:55:33,167 It's subtle, but I rattled this acronym off I think just once weeks ago, SMTP. 1182 00:55:33,167 --> 00:55:34,750 Does anyone know what that stands for? 1183 00:55:34,750 --> 00:55:36,416 AUDIENCE: Simple mail transfer protocol? 1184 00:55:36,416 --> 00:55:39,640 DAVID MALAN: Yeah, simple mail transfer protocol-- email, that is. 1185 00:55:39,640 --> 00:55:41,440 So Python comes with built in functionality 1186 00:55:41,440 --> 00:55:43,870 via which you can send emails, and this is exactly what I 1187 00:55:43,870 --> 00:55:45,580 did when I first made this website. 1188 00:55:45,580 --> 00:55:47,650 Didn't know anything about databases, I didn't know anything 1189 00:55:47,650 --> 00:55:50,320 about saving things to files just yet, I was still learning. 1190 00:55:50,320 --> 00:55:53,050 But I didn't realize, hm, I could use programming 1191 00:55:53,050 --> 00:55:56,530 to send an email to the proctor or the RA who was overseeing the sports 1192 00:55:56,530 --> 00:55:59,470 program so that they could just save it in a folder 1193 00:55:59,470 --> 00:56:00,660 and know who had registered. 1194 00:56:00,660 --> 00:56:03,040 It's not super user friendly, but it at least 1195 00:56:03,040 --> 00:56:06,040 got the job done because they were then able to track everything. 1196 00:56:06,040 --> 00:56:11,030 So in this program, notice that I have my route for my form. 1197 00:56:11,030 --> 00:56:14,217 And I have this register route but a few new lines of code. 1198 00:56:14,217 --> 00:56:17,050 And you would only know how to do this by reading the documentation. 1199 00:56:17,050 --> 00:56:20,140 But in this case here, notice what I'm doing in my register route. 1200 00:56:20,140 --> 00:56:25,600 I'm first getting the user's name and their email this time and their dorm. 1201 00:56:25,600 --> 00:56:26,650 Then I'm error checking. 1202 00:56:26,650 --> 00:56:29,170 If they didn't give me a name, or their email, or the dorm, 1203 00:56:29,170 --> 00:56:32,230 render failure.html to apprise them as much. 1204 00:56:32,230 --> 00:56:34,494 Then go ahead and do these lines of code. 1205 00:56:34,494 --> 00:56:36,910 And this is more of a mouthful, and you would only, again, 1206 00:56:36,910 --> 00:56:38,284 know this from the documentation. 1207 00:56:38,284 --> 00:56:40,570 But it turns out if you read the documentation 1208 00:56:40,570 --> 00:56:46,160 for this SMTP lib or library, you can use lines of code like this as follows. 1209 00:56:46,160 --> 00:56:49,870 You can tell the library what server to use for sending email. 1210 00:56:49,870 --> 00:56:52,000 And it turns out if you read Gmail's documentation, 1211 00:56:52,000 --> 00:56:56,110 you can use smtp.gmail.com to automatically send e-mails not using 1212 00:56:56,110 --> 00:56:57,970 the web UI, but using code. 1213 00:56:57,970 --> 00:57:00,770 587 is the TCP port that they use. 1214 00:57:00,770 --> 00:57:04,180 So it's not 80, it's not 443, it's 587 by convention. 1215 00:57:04,180 --> 00:57:07,690 Starttls, if you read the documentation, says turn on encryption. 1216 00:57:07,690 --> 00:57:11,020 So the email is encrypted between you and Gmail. 1217 00:57:11,020 --> 00:57:13,750 Then go ahead and log in with a certain username and password. 1218 00:57:13,750 --> 00:57:17,830 I created an account in advance called jharvard@cs50.net, and my password 1219 00:57:17,830 --> 00:57:19,565 is in my IDE's environment. 1220 00:57:19,565 --> 00:57:21,940 I stored it elsewhere so that it's not visible on screen, 1221 00:57:21,940 --> 00:57:24,610 otherwise people could send emails as John. 1222 00:57:24,610 --> 00:57:27,979 Then I go ahead and call literally a function called send mail. 1223 00:57:27,979 --> 00:57:29,770 And if you read the documentation, this one 1224 00:57:29,770 --> 00:57:33,070 takes as argument who you want to send email to, 1225 00:57:33,070 --> 00:57:36,490 the contents of the email that you want to send, 1226 00:57:36,490 --> 00:57:39,490 and the message that you actually want to send here. 1227 00:57:39,490 --> 00:57:42,340 Or rather, this is the from address, the to address, 1228 00:57:42,340 --> 00:57:44,830 and the actual message that you want to send. 1229 00:57:44,830 --> 00:57:48,070 After that, you just go ahead and render template and assume success. 1230 00:57:48,070 --> 00:57:49,720 I could add more error checking, like I should probably 1231 00:57:49,720 --> 00:57:52,360 check if anything went wrong here, but I'm keeping it simple. 1232 00:57:52,360 --> 00:57:56,050 But these new lines that are highlighted actually send an email. 1233 00:57:56,050 --> 00:57:56,990 So let's try this. 1234 00:57:56,990 --> 00:58:02,320 Let me go into froshims2 and let me go ahead and do Flask run. 1235 00:58:02,320 --> 00:58:06,030 Let me go ahead and open up the page here, slash. 1236 00:58:06,030 --> 00:58:09,290 And notice I do, indeed, have a second field for text now. 1237 00:58:09,290 --> 00:58:12,700 So this will be David, and this will be-- 1238 00:58:12,700 --> 00:58:16,900 let's see, how about let's go ahead and just register not myself, 1239 00:58:16,900 --> 00:58:19,770 since it's not my email account, but John Harvard who we claim's 1240 00:58:19,770 --> 00:58:22,960 email is cs50.net, jharvard thereat. 1241 00:58:22,960 --> 00:58:25,730 And he lives in say, Weld. 1242 00:58:25,730 --> 00:58:29,330 Let's go ahead and click Register. 1243 00:58:29,330 --> 00:58:31,422 All right, it's taking a little longer this time, 1244 00:58:31,422 --> 00:58:33,630 but it was doing a little more work sending an email. 1245 00:58:33,630 --> 00:58:38,920 So now let's try to go to gmail.com, open this up. 1246 00:58:38,920 --> 00:58:39,420 Ooh. 1247 00:58:39,420 --> 00:58:41,760 In my inbox, you are registered. 1248 00:58:41,760 --> 00:58:45,391 If I open this up, notice jharvard@cs50.net 1249 00:58:45,391 --> 00:58:48,390 has sent me an email by a BC seed, at least keep part of the information 1250 00:58:48,390 --> 00:58:48,890 private. 1251 00:58:48,890 --> 00:58:52,950 And it just says in the body of the message if I move the cursor, 1252 00:58:52,950 --> 00:58:54,390 you are registered. 1253 00:58:54,390 --> 00:58:56,790 So I did a little more back in 1997, but I 1254 00:58:56,790 --> 00:58:59,749 included like the user's name, and their email address, and their dorm, 1255 00:58:59,749 --> 00:59:03,081 and maybe their phone number or whatnot, and the sports they were interested in. 1256 00:59:03,081 --> 00:59:04,360 But the idea is exactly that. 1257 00:59:04,360 --> 00:59:07,800 You can send any information you want just by now using code. 1258 00:59:07,800 --> 00:59:12,470 You could not do that with HTML or with CSS alone. 1259 00:59:12,470 --> 00:59:16,130 Any questions, then, on this? 1260 00:59:16,130 --> 00:59:16,780 Yeah? 1261 00:59:16,780 --> 00:59:19,405 AUDIENCE: Last week when we wrote code in Python we had to like 1262 00:59:19,405 --> 00:59:24,275 say if name equals the function to like execute that. 1263 00:59:24,275 --> 00:59:26,030 How come in this we're not doing that? 1264 00:59:26,030 --> 00:59:27,696 DAVID MALAN: That was all in JavaScript. 1265 00:59:27,696 --> 00:59:31,060 So that allusion to if name equals, and then you assign it to a function, 1266 00:59:31,060 --> 00:59:35,860 I think you're referring to our JavaScript examples, no? 1267 00:59:35,860 --> 00:59:36,380 OK. 1268 00:59:36,380 --> 00:59:38,090 So we'll actually come back to that in a little bit 1269 00:59:38,090 --> 00:59:39,980 where we reintroduce a bit of JavaScript, 1270 00:59:39,980 --> 00:59:42,680 which actually gives us some more functionality reminiscent 1271 00:59:42,680 --> 00:59:43,610 of those examples. 1272 00:59:43,610 --> 00:59:44,590 Other question? 1273 00:59:44,590 --> 00:59:47,777 AUDIENCE: What email address did you send that email from, 1274 00:59:47,777 --> 00:59:50,110 and don't you need to enter like a password to make sure 1275 00:59:50,110 --> 00:59:52,282 that no one just randomly sends email? 1276 00:59:52,282 --> 00:59:54,240 DAVID MALAN: Yeah, it's a really good question. 1277 00:59:54,240 --> 00:59:57,440 So via what email address did I send that, and to whom was it sent? 1278 00:59:57,440 --> 01:00:01,310 So again, this is the from address, this is the to address, 1279 01:00:01,310 --> 01:00:02,540 and this is now the message. 1280 01:00:02,540 --> 01:00:06,170 And just because I only have one email account open, I had John send himself 1281 01:00:06,170 --> 01:00:07,670 an email in this case. 1282 01:00:07,670 --> 01:00:11,330 Theoretically if I were running the freshmen intramural sports program, 1283 01:00:11,330 --> 01:00:16,340 I could try to do this and change this from address to be myself. 1284 01:00:16,340 --> 01:00:19,850 The catch is that Gmail actually has protections in place so that if you've 1285 01:00:19,850 --> 01:00:23,390 logged in as jharvard with his password, then 1286 01:00:23,390 --> 01:00:26,090 the email, no matter what you specify as the from address, 1287 01:00:26,090 --> 01:00:29,150 is actually going to be overridden to be from John Harvard. 1288 01:00:29,150 --> 01:00:32,010 However, this does speak to the potential insecurity of email. 1289 01:00:32,010 --> 01:00:34,010 If you don't use Gmail but you use a third party 1290 01:00:34,010 --> 01:00:36,620 service that is not so rigorous with its error checking, 1291 01:00:36,620 --> 01:00:40,920 it is incredibly easy to fake emails from one person to another. 1292 01:00:40,920 --> 01:00:42,920 I mean, look through your spam folder sometime. 1293 01:00:42,920 --> 01:00:45,710 Most of those people who send you those spams don't exist. 1294 01:00:45,710 --> 01:00:48,560 Like, the email addresses and/or the names are fake. 1295 01:00:48,560 --> 01:00:52,190 And yet they might appear to actually be from a sibling of yours, a family 1296 01:00:52,190 --> 01:00:55,610 member, or a friend, even though those humans did not send e-mails. 1297 01:00:55,610 --> 01:00:57,890 And that's because some spammer has written code 1298 01:00:57,890 --> 01:00:59,810 like this in Python or some other language, 1299 01:00:59,810 --> 01:01:03,740 but has overridden these fields, but used a server that's not Gmail 1300 01:01:03,740 --> 01:01:07,200 that doesn't enforce these policies. 1301 01:01:07,200 --> 01:01:09,970 Other questions? 1302 01:01:09,970 --> 01:01:12,880 Fun fact, also in 1995, I learned how to send-- 1303 01:01:12,880 --> 01:01:15,414 or how to change the from address on an email. 1304 01:01:15,414 --> 01:01:17,830 And turns out at Harvard there's this entity called the ad 1305 01:01:17,830 --> 01:01:19,270 board who doesn't like doing this. 1306 01:01:19,270 --> 01:01:22,825 So don't do that. 1307 01:01:22,825 --> 01:01:25,950 Sometimes there's human defenses in place for this, not just technological. 1308 01:01:25,950 --> 01:01:30,490 Thankfully, my friend whom I faked an email from did not-- 1309 01:01:30,490 --> 01:01:31,870 it worked out OK. 1310 01:01:31,870 --> 01:01:33,250 All right. 1311 01:01:33,250 --> 01:01:36,550 You have now great power, don't use it for evil. 1312 01:01:36,550 --> 01:01:40,075 All right, so let's go ahead now and do another example, but that takes this 1313 01:01:40,075 --> 01:01:44,500 a further step, adding, finally some persistence of information. 1314 01:01:44,500 --> 01:01:48,940 Let's go ahead into froshims3 now and open up application.py. 1315 01:01:48,940 --> 01:01:53,977 So recall that we can use CSV files-- comma separated value files-- 1316 01:01:53,977 --> 01:01:55,810 to create the illusion of like spreadsheets, 1317 01:01:55,810 --> 01:01:58,120 but now we're actually going to create them ourselves. 1318 01:01:58,120 --> 01:02:00,100 The code for this is a little more involved, 1319 01:02:00,100 --> 01:02:03,020 and the only thing I've changed now really is the register method. 1320 01:02:03,020 --> 01:02:07,325 So in version one of this code, I saved it in a global list just in memory. 1321 01:02:07,325 --> 01:02:09,700 That was not good because it gets thrown away too easily. 1322 01:02:09,700 --> 01:02:11,260 Version two of this we just sent an email 1323 01:02:11,260 --> 01:02:12,730 to the proctor who runs the program. 1324 01:02:12,730 --> 01:02:15,400 That was a little better, because at least they can then save the email. 1325 01:02:15,400 --> 01:02:18,400 Version three, we're going to use a very lightweight database called 1326 01:02:18,400 --> 01:02:22,360 the CSV file that saves it to my hard drive permanently. 1327 01:02:22,360 --> 01:02:25,280 So even when the server stops, the data is still there. 1328 01:02:25,280 --> 01:02:27,230 So in Python, how does this work? 1329 01:02:27,230 --> 01:02:30,890 Well, notice that I've improved my register route this time as follows. 1330 01:02:30,890 --> 01:02:33,479 If the user did not give me their name or dorm, 1331 01:02:33,479 --> 01:02:35,020 then I go ahead and render a failure. 1332 01:02:35,020 --> 01:02:36,860 That's pretty much the same logic as before, 1333 01:02:36,860 --> 01:02:39,110 but I didn't bother declaring the variables this time, 1334 01:02:39,110 --> 01:02:41,270 I just called the functions directly. 1335 01:02:41,270 --> 01:02:44,730 Here's a new line of code that might be reminiscent of some of your past file 1336 01:02:44,730 --> 01:02:45,730 I/O code. 1337 01:02:45,730 --> 01:02:50,440 In line 16 here, I'm telling Python to go ahead and open a file called 1338 01:02:50,440 --> 01:02:53,770 registered.csv quote-unquote a. 1339 01:02:53,770 --> 01:02:56,600 So we've seen R, we've seen W for read and write. 1340 01:02:56,600 --> 01:02:59,400 Anyone recall what a is, or no? 1341 01:02:59,400 --> 01:03:00,160 AUDIENCE: Append. 1342 01:03:00,160 --> 01:03:02,493 DAVID MALAN: It happens to mean append, which means just 1343 01:03:02,493 --> 01:03:04,180 add a row to the file, which is nice. 1344 01:03:04,180 --> 01:03:06,790 Because if there's already students registered, when a new one registers 1345 01:03:06,790 --> 01:03:08,831 we just want to append to the bottom of the file. 1346 01:03:08,831 --> 01:03:12,310 Quote-unquote a is supported by Python with this open function. 1347 01:03:12,310 --> 01:03:15,220 That gives me back a reference or like a pointer to file, 1348 01:03:15,220 --> 01:03:17,740 even though Python does not have pointers. 1349 01:03:17,740 --> 01:03:19,100 Then this is the new feature. 1350 01:03:19,100 --> 01:03:21,340 And here, too, you'd only know this from having seen an example 1351 01:03:21,340 --> 01:03:22,900 or you reading the documentation. 1352 01:03:22,900 --> 01:03:26,900 You can use the CSV library, which we'll see as imported up above. 1353 01:03:26,900 --> 01:03:31,431 And you can ask for a writer, a piece of code that writes out-- that is, 1354 01:03:31,431 --> 01:03:31,930 creates-- 1355 01:03:31,930 --> 01:03:33,190 CSV files. 1356 01:03:33,190 --> 01:03:35,620 And specifically, you want to write to this file. 1357 01:03:35,620 --> 01:03:38,320 That library-- the CSV library-- comes with a function 1358 01:03:38,320 --> 01:03:40,450 called write row, which does what it says. 1359 01:03:40,450 --> 01:03:43,960 If you pass it in a comma separated list of fields 1360 01:03:43,960 --> 01:03:46,810 that you want to represent your first column, your second column, 1361 01:03:46,810 --> 01:03:49,665 and your third column, it will handle the writing for you 1362 01:03:49,665 --> 01:03:51,790 so you don't have to get into the weeds of file I/O 1363 01:03:51,790 --> 01:03:53,800 like you did several problem sets ago. 1364 01:03:53,800 --> 01:03:54,970 Notice the subtlety. 1365 01:03:54,970 --> 01:03:58,510 You do need to have these second pair of parentheses, 1366 01:03:58,510 --> 01:04:00,850 because technically what you're giving it is a tuple. 1367 01:04:00,850 --> 01:04:02,930 We talked very briefly about that last week, 1368 01:04:02,930 --> 01:04:06,250 which is just like an x comma y pair, or latitude comma longitude. 1369 01:04:06,250 --> 01:04:07,120 Same idea here. 1370 01:04:07,120 --> 01:04:11,230 First column, second column, and so forth is a so-called tuple. 1371 01:04:11,230 --> 01:04:13,940 Then I close the file, then I render the template. 1372 01:04:13,940 --> 01:04:15,920 So what does this actually do for me? 1373 01:04:15,920 --> 01:04:19,390 Well, let me go into my folder froshims3 here. 1374 01:04:19,390 --> 01:04:22,360 And notice register.csv at the moment is empty. 1375 01:04:22,360 --> 01:04:23,560 This is a CSV file. 1376 01:04:23,560 --> 01:04:25,490 Nothing's going on inside of that. 1377 01:04:25,490 --> 01:04:27,340 There's no one registered yet. 1378 01:04:27,340 --> 01:04:32,260 But let me go ahead, then, and go into froshims3, run Flask run. 1379 01:04:32,260 --> 01:04:33,970 Let me go ahead and load this up. 1380 01:04:33,970 --> 01:04:37,460 And you'll see the same kind of form, but also a new link. 1381 01:04:37,460 --> 01:04:40,760 Notice that no one's registered yet if I click on that link. 1382 01:04:40,760 --> 01:04:46,220 But if I go into here and register David from Matthews and click Register, 1383 01:04:46,220 --> 01:04:48,310 now it claims I am registered really. 1384 01:04:48,310 --> 01:04:52,156 Let me click this link and notice that it's very small on the screen, 1385 01:04:52,156 --> 01:04:54,280 but slash registered is where this is going to lead 1386 01:04:54,280 --> 01:04:56,470 me, which is just where I was before. 1387 01:04:56,470 --> 01:04:58,984 You see that now David from Matthews registered. 1388 01:04:58,984 --> 01:05:00,400 Let me go back to the form itself. 1389 01:05:00,400 --> 01:05:02,860 Let's register, say, Brian from Pennypacker. 1390 01:05:02,860 --> 01:05:04,094 Click Register. 1391 01:05:04,094 --> 01:05:05,510 He, too, is apparently registered. 1392 01:05:05,510 --> 01:05:06,580 Let's click that link. 1393 01:05:06,580 --> 01:05:07,870 Brian from Pennypacker. 1394 01:05:07,870 --> 01:05:09,760 All right, so where is this data going? 1395 01:05:09,760 --> 01:05:13,360 Let me go back to the IDE, close my registered CSV file, 1396 01:05:13,360 --> 01:05:16,090 because it's probably changed and open it up. 1397 01:05:16,090 --> 01:05:19,090 And voila, indeed, it's prompting me to reload it. 1398 01:05:19,090 --> 01:05:20,330 There is the file. 1399 01:05:20,330 --> 01:05:25,270 And notice David comma Matthews, Brian comma Pennypacker, all of those rows 1400 01:05:25,270 --> 01:05:26,270 were written out for me. 1401 01:05:26,270 --> 01:05:28,450 So now I actually have a database. 1402 01:05:28,450 --> 01:05:31,510 And even though it's kind of a simple database, you know what I can do? 1403 01:05:31,510 --> 01:05:34,990 Let me go ahead and right click or control click on it in the IDE, 1404 01:05:34,990 --> 01:05:37,360 download it into my Downloads folder. 1405 01:05:37,360 --> 01:05:39,340 And then if I actually open this thing, if I 1406 01:05:39,340 --> 01:05:42,350 have Excel installed or Apple Numbers, which 1407 01:05:42,350 --> 01:05:47,690 is the first time I've ever used it, let me go ahead and open that file. 1408 01:05:47,690 --> 01:05:49,400 Opening register.csv. 1409 01:05:49,400 --> 01:05:51,690 And voila, here now is a file. 1410 01:05:51,690 --> 01:05:54,380 And Numbers is formatting it in kind of a funky way, 1411 01:05:54,380 --> 01:05:56,210 but it is showing rows and columns. 1412 01:05:56,210 --> 01:05:58,970 Those of you who are more familiar with Excel we can do that, too. 1413 01:05:58,970 --> 01:06:00,560 Let me go down here. 1414 01:06:00,560 --> 01:06:03,200 Let me go into my Downloads folder. 1415 01:06:03,200 --> 01:06:07,040 Control click or right click here, and this time open it with Microsoft Excel. 1416 01:06:07,040 --> 01:06:10,730 And if you've seen Excel before, we'll probably see a very similar UI. 1417 01:06:10,730 --> 01:06:12,680 Because anytime Excel or Numbers-- 1418 01:06:12,680 --> 01:06:14,330 OK, first time I've used Excel. 1419 01:06:14,330 --> 01:06:18,500 So that, too, will open up some rows and columns, as well. 1420 01:06:18,500 --> 01:06:20,990 So CSV files are just very lightweight spreadsheets. 1421 01:06:20,990 --> 01:06:24,159 But what's cool about them is that you can create them so easily. 1422 01:06:24,159 --> 01:06:25,700 You just have to put commas in there. 1423 01:06:25,700 --> 01:06:29,420 Now, as an aside, can you contrive a user's input 1424 01:06:29,420 --> 01:06:32,660 that could potentially break a CSV file? 1425 01:06:32,660 --> 01:06:37,550 What could a human type in that could potentially break your own CSV files? 1426 01:06:37,550 --> 01:06:38,460 A comma, right? 1427 01:06:38,460 --> 01:06:42,150 If it's like David Mayland comma junior, or something like that. 1428 01:06:42,150 --> 01:06:45,000 Or anything with weird punctuation. 1429 01:06:45,000 --> 01:06:46,530 This is why you use libraries. 1430 01:06:46,530 --> 01:06:49,020 That CSV library in this code, which we're 1431 01:06:49,020 --> 01:06:53,100 importing at the very top of this version 3 of the code, 1432 01:06:53,100 --> 01:06:55,830 is actually handling all of that complexity for us. 1433 01:06:55,830 --> 01:06:58,950 When the library encounters David Mayland comma junior if that's 1434 01:06:58,950 --> 01:07:00,900 the user's input, it will then additionally 1435 01:07:00,900 --> 01:07:03,720 put quotes around my whole name, thereby making sure 1436 01:07:03,720 --> 01:07:06,660 that my comma is inside quotes and not, therefore, 1437 01:07:06,660 --> 01:07:10,450 confused with the special comma that demarcates the start of other columns. 1438 01:07:10,450 --> 01:07:12,690 So again, that's why you don't reinvent the wheel, 1439 01:07:12,690 --> 01:07:14,470 because corner cases like that arise. 1440 01:07:14,470 --> 01:07:17,640 Well, what about slash registered, which is this list that's 1441 01:07:17,640 --> 01:07:18,960 generating an unordered list? 1442 01:07:18,960 --> 01:07:20,320 Let's see how that works. 1443 01:07:20,320 --> 01:07:23,280 If I scroll down to this code, notice that it's not 1444 01:07:23,280 --> 01:07:25,920 just a simple matter of grabbing a global variable, 1445 01:07:25,920 --> 01:07:28,230 because there is no global variable anymore. 1446 01:07:28,230 --> 01:07:30,790 Now I have to read it from that CSV file. 1447 01:07:30,790 --> 01:07:34,630 So here's three new lines of code that work as follows. 1448 01:07:34,630 --> 01:07:38,730 I'm going to go ahead and open this file, register.csv, in Read mode 1449 01:07:38,730 --> 01:07:40,290 this time, not append. 1450 01:07:40,290 --> 01:07:44,400 I'm going to go ahead now and say hey Python, use the CSV reader-- 1451 01:07:44,400 --> 01:07:45,960 which is the opposite of writer-- 1452 01:07:45,960 --> 01:07:47,190 on that file. 1453 01:07:47,190 --> 01:07:50,719 And then, hey Python, go ahead and turn that whole reader into a list. 1454 01:07:50,719 --> 01:07:53,010 So you'd only know this from reading the documentation. 1455 01:07:53,010 --> 01:07:54,330 It turns out this is the recommendation. 1456 01:07:54,330 --> 01:07:57,540 If you want to take a reader and just read the whole thing into memory 1457 01:07:57,540 --> 01:08:00,600 at once and convert it to a Python list, you literally just pass it 1458 01:08:00,600 --> 01:08:01,890 to this list function. 1459 01:08:01,890 --> 01:08:04,260 That gives me a list I'm going to call students, 1460 01:08:04,260 --> 01:08:06,849 and then I can do my same code as before. 1461 01:08:06,849 --> 01:08:08,640 For good measure, I should probably do what 1462 01:08:08,640 --> 01:08:13,260 I did last time, which is file.close to close the file, as well, just 1463 01:08:13,260 --> 01:08:15,821 to make sure it's closed the next time it's opened. 1464 01:08:15,821 --> 01:08:18,779 But I can actually simplify this, and you'll see more of these examples 1465 01:08:18,779 --> 01:08:19,529 online. 1466 01:08:19,529 --> 01:08:23,310 It's actually more conventional in Python not to do this, 1467 01:08:23,310 --> 01:08:25,950 but instead to change your code as follows. 1468 01:08:25,950 --> 01:08:31,080 To not bother closing it explicitly, to instead use a keyword called with 1469 01:08:31,080 --> 01:08:35,370 to instead put the variable name back there and indent everything underneath. 1470 01:08:35,370 --> 01:08:38,010 Doesn't matter for our purposes which one you do. 1471 01:08:38,010 --> 01:08:39,430 The first one was correct. 1472 01:08:39,430 --> 01:08:40,630 The second one is correct. 1473 01:08:40,630 --> 01:08:43,410 This is just more conventional, if only because it handles 1474 01:08:43,410 --> 01:08:44,979 the closing of the file for you. 1475 01:08:44,979 --> 01:08:47,520 So if you see this online, that's all that's happening there. 1476 01:08:47,520 --> 01:08:53,100 But it's just like in C doing fopen and fclose, or in this case open and close 1477 01:08:53,100 --> 01:08:54,729 like I had a moment ago. 1478 01:08:54,729 --> 01:08:56,136 Any questions, then? 1479 01:08:56,136 --> 01:08:58,110 AUDIENCE: How would you handle duplicates? 1480 01:08:58,110 --> 01:08:59,609 DAVID MALAN: How would I duplicates? 1481 01:08:59,609 --> 01:09:00,240 good question. 1482 01:09:00,240 --> 01:09:03,600 So haven't handled duplicates here at all, and David from Matthews 1483 01:09:03,600 --> 01:09:05,310 could register again and again. 1484 01:09:05,310 --> 01:09:07,080 But logically what might I do? 1485 01:09:07,080 --> 01:09:10,439 Well, it probably belongs here in my register route. 1486 01:09:10,439 --> 01:09:14,439 I probably want to do more error checking than just these two lines. 1487 01:09:14,439 --> 01:09:17,640 Because what I probably want to do to see if David from Matthews 1488 01:09:17,640 --> 01:09:20,729 is already registered is open the CSV file, 1489 01:09:20,729 --> 01:09:26,069 iterate over its lines looking for David and for Matthews on the same line 1490 01:09:26,069 --> 01:09:29,340 and then show a failure to the user if he or she is 1491 01:09:29,340 --> 01:09:31,200 trying to register for a second time. 1492 01:09:31,200 --> 01:09:33,660 I've not made it easy with this code, and frankly that's 1493 01:09:33,660 --> 01:09:35,939 going to be so much easier next week with SQL. 1494 01:09:35,939 --> 01:09:37,979 SQL, this other language for databases, will 1495 01:09:37,979 --> 01:09:41,109 make it easy to search data that has already been saved. 1496 01:09:41,109 --> 01:09:43,069 CSV files do not make this easy. 1497 01:09:43,069 --> 01:09:46,200 It's doable, but you have to write more lines of code. 1498 01:09:46,200 --> 01:09:47,479 So more on that to come. 1499 01:09:47,479 --> 01:09:48,290 Other questions? 1500 01:09:48,290 --> 01:09:51,270 1501 01:09:51,270 --> 01:09:55,470 All right, so let's skip ahead to one final example, 1502 01:09:55,470 --> 01:10:00,400 froshim6, which we'll do something a little more for us here. 1503 01:10:00,400 --> 01:10:04,140 So if I go ahead into froshim6, notice that if I 1504 01:10:04,140 --> 01:10:08,700 do Flask run, and go back to the website here, and reload the screen, 1505 01:10:08,700 --> 01:10:13,320 and I go ahead and give you my name, but no, I'm not going to give you my dorm, 1506 01:10:13,320 --> 01:10:14,680 we have this feature. 1507 01:10:14,680 --> 01:10:18,450 It's ugly again, but where did we see this kind of functionality 1508 01:10:18,450 --> 01:10:19,880 when the user does not cooperate? 1509 01:10:19,880 --> 01:10:23,350 1510 01:10:23,350 --> 01:10:25,275 Or how did I implement this, apparently? 1511 01:10:25,275 --> 01:10:26,150 AUDIENCE: JavaScript? 1512 01:10:26,150 --> 01:10:27,690 DAVID MALAN: Yeah, JavaScript. 1513 01:10:27,690 --> 01:10:30,690 So it turns out that with Python, you can obviously 1514 01:10:30,690 --> 01:10:33,780 validate the user's input on the server by just checking what's 1515 01:10:33,780 --> 01:10:37,710 in request.args or request.form and then yell at the user success or failure 1516 01:10:37,710 --> 01:10:38,770 accordingly. 1517 01:10:38,770 --> 01:10:42,220 But you can also use JavaScript-- and honestly, we did this two weeks ago, 1518 01:10:42,220 --> 01:10:44,640 so we just seem to be solving the same problems again. 1519 01:10:44,640 --> 01:10:46,780 So how do you think about this? 1520 01:10:46,780 --> 01:10:50,509 Should I be checking for the user's name and dorm in JavaScript? 1521 01:10:50,509 --> 01:10:53,175 Should I be checking for the user's name and dorm on the server? 1522 01:10:53,175 --> 01:10:56,220 1523 01:10:56,220 --> 01:10:59,805 I mean, mixed messages now. 1524 01:10:59,805 --> 01:11:01,190 AUDIENCE: Whatever's fastest. 1525 01:11:01,190 --> 01:11:02,000 DAVID MALAN: Whatever fastest. 1526 01:11:02,000 --> 01:11:04,370 That's a pretty good heuristic to use, what's fastest. 1527 01:11:04,370 --> 01:11:07,010 And we can make it prettier by using Bootstrap or some library 1528 01:11:07,010 --> 01:11:10,790 to give you like a colorful box, or red error text or something like that. 1529 01:11:10,790 --> 01:11:14,055 So which probably is faster, Python or JavaScript? 1530 01:11:14,055 --> 01:11:14,930 AUDIENCE: JavaScript. 1531 01:11:14,930 --> 01:11:15,929 DAVID MALAN: JavaScript. 1532 01:11:15,929 --> 01:11:18,420 Why, is JavaScript just a better, faster language? 1533 01:11:18,420 --> 01:11:20,360 AUDIENCE: You're not creating it [INAUDIBLE] 1534 01:11:20,360 --> 01:11:20,850 DAVID MALAN: Say again? 1535 01:11:20,850 --> 01:11:22,778 AUDIENCE: You're not creating it on a new server, 1536 01:11:22,778 --> 01:11:24,230 so it's all happening on the same-- 1537 01:11:24,230 --> 01:11:25,100 DAVID MALAN: That's why, yeah. 1538 01:11:25,100 --> 01:11:27,766 We don't have to get into the religious debate of which language 1539 01:11:27,766 --> 01:11:30,800 is better or faster, but where they're running is certainly important. 1540 01:11:30,800 --> 01:11:34,140 JavaScript is running, recall, by definition, in the browser. 1541 01:11:34,140 --> 01:11:36,140 It is sent as JavaScript code to the browser 1542 01:11:36,140 --> 01:11:37,940 which then executes it client side. 1543 01:11:37,940 --> 01:11:40,942 Python by definition today is doing everything server side. 1544 01:11:40,942 --> 01:11:42,650 And indeed, the browser doesn't even know 1545 01:11:42,650 --> 01:11:47,240 Python is involved, because all it gets is the HTML code that results. 1546 01:11:47,240 --> 01:11:49,910 So OK, that seems to be an argument for not 1547 01:11:49,910 --> 01:11:53,530 doing all of the new work we did today with if not name, if not dorm, 1548 01:11:53,530 --> 01:11:55,910 and all of that, and just use JavaScript. 1549 01:11:55,910 --> 01:12:00,080 But the problem is that if you get a little sloppy or a little clever 1550 01:12:00,080 --> 01:12:03,050 and only implement your error checking client side. 1551 01:12:03,050 --> 01:12:06,230 Because as you say, it's faster, and frankly once I make it prettier, 1552 01:12:06,230 --> 01:12:09,330 it's just going to be more interactive and more seamless. 1553 01:12:09,330 --> 01:12:12,860 The problem is you can't and should not trust users. 1554 01:12:12,860 --> 01:12:15,320 Suppose that I'm a malicious user and I just 1555 01:12:15,320 --> 01:12:18,910 want to inject some bogus data into your website, or I want to spam you, 1556 01:12:18,910 --> 01:12:22,550 or subscribe 1,000 freshmen who don't actually exist, or just 1557 01:12:22,550 --> 01:12:24,592 generally create problems for you. 1558 01:12:24,592 --> 01:12:26,300 Well, you might think, well, that's OK, I 1559 01:12:26,300 --> 01:12:28,420 have some defenses in place, and JavaScript code, 1560 01:12:28,420 --> 01:12:31,670 and this adversary is going to get very quick feedback, very pretty 1561 01:12:31,670 --> 01:12:34,880 feedback that they've not provided these various fields. 1562 01:12:34,880 --> 01:12:38,600 But honestly, you can't trust anything ever coming from the human. 1563 01:12:38,600 --> 01:12:41,150 If I open up Chrome's developer tools, and I 1564 01:12:41,150 --> 01:12:45,770 go to this down here to the dot dot dot menu, and I go to Settings, 1565 01:12:45,770 --> 01:12:50,120 and I go down here, there. 1566 01:12:50,120 --> 01:12:52,670 That's all it takes to disable all of your hard work. 1567 01:12:52,670 --> 01:12:54,470 He or she can just open up their browser-- 1568 01:12:54,470 --> 01:12:55,730 Chrome or something else-- 1569 01:12:55,730 --> 01:12:57,170 turn off JavaScript. 1570 01:12:57,170 --> 01:13:00,200 So now when I actually submit this form, there's 1571 01:13:00,200 --> 01:13:02,960 going to be no on-submit checking, no on-click handling. 1572 01:13:02,960 --> 01:13:04,260 All of that is disabled. 1573 01:13:04,260 --> 01:13:07,400 So if I go ahead and click Register, I at least 1574 01:13:07,400 --> 01:13:11,520 still, in this version of froshims, have server side checking, as well. 1575 01:13:11,520 --> 01:13:14,420 So this might be a little frustrating, but it's kind of the reality. 1576 01:13:14,420 --> 01:13:16,700 It is perfectly fine to use JavaScript code 1577 01:13:16,700 --> 01:13:19,820 and use client side code to give the user a better experience-- a.k.a. 1578 01:13:19,820 --> 01:13:21,920 UX, user experience. 1579 01:13:21,920 --> 01:13:24,530 But you can't cut corners and not implement 1580 01:13:24,530 --> 01:13:27,230 the same kind of logic server side because you 1581 01:13:27,230 --> 01:13:28,490 need to defend against this. 1582 01:13:28,490 --> 01:13:30,865 Otherwise bogus data is going to end up in your database, 1583 01:13:30,865 --> 01:13:32,120 things are going to go wrong. 1584 01:13:32,120 --> 01:13:35,850 Never, ever, ever trust the user. 1585 01:13:35,850 --> 01:13:37,192 Any questions? 1586 01:13:37,192 --> 01:13:38,776 AUDIENCE: Can you do the same via CSS? 1587 01:13:38,776 --> 01:13:40,525 DAVID MALAN: Can you do the same with CSS? 1588 01:13:40,525 --> 01:13:43,130 AUDIENCE: Yes, can you [INAUDIBLE] JavaScript [INAUDIBLE]?? 1589 01:13:43,130 --> 01:13:44,840 DAVID MALAN: Not with CSS alone. 1590 01:13:44,840 --> 01:13:47,990 You can use CSS to make the error messages far prettier, yes, 1591 01:13:47,990 --> 01:13:51,237 but not logically enough with CSS alone. 1592 01:13:51,237 --> 01:13:54,320 And in fact, just to give you a sense now how you can make things prettier 1593 01:13:54,320 --> 01:13:58,700 since I keep alluding to better design skills than the ones I'm showing here. 1594 01:13:58,700 --> 01:14:01,550 If we go to Bootstrap, this very popular, free, and open source 1595 01:14:01,550 --> 01:14:05,070 library for CSS, it actually has some interactive features, as well. 1596 01:14:05,070 --> 01:14:08,360 And if I go under components in the documentation and I scroll down 1597 01:14:08,360 --> 01:14:11,630 and I go to forms, you'll see, one, notice 1598 01:14:11,630 --> 01:14:14,230 that these forms are already way prettier than the ones 1599 01:14:14,230 --> 01:14:15,230 I've been making, right? 1600 01:14:15,230 --> 01:14:17,600 It's like black text, and gray text, and small text. 1601 01:14:17,600 --> 01:14:19,580 It just looks nicer and cleaner. 1602 01:14:19,580 --> 01:14:21,080 But it's relatively easy to do this. 1603 01:14:21,080 --> 01:14:22,954 And indeed, for the next problems that you'll 1604 01:14:22,954 --> 01:14:26,000 be welcome to copy and paste some of this sample code and HTML, 1605 01:14:26,000 --> 01:14:29,270 use Bootstrap CSS just to make your forms prettier. 1606 01:14:29,270 --> 01:14:32,400 But what it can really do if I go to the sub menu over here, 1607 01:14:32,400 --> 01:14:34,840 notice that there's this validation section in Bootstrap. 1608 01:14:34,840 --> 01:14:36,300 And other libraries have this, too. 1609 01:14:36,300 --> 01:14:38,480 And you'll want to read the actual documentation. 1610 01:14:38,480 --> 01:14:41,780 But if I just scroll down for a while, here's a sample form in Bootstrap. 1611 01:14:41,780 --> 01:14:45,440 It already looks a little prettier than anything I've made in just raw HTML. 1612 01:14:45,440 --> 01:14:50,420 But notice if I don't cooperate, you can do really cool validation of forms 1613 01:14:50,420 --> 01:14:53,030 with green and red text if the user does or doesn't 1614 01:14:53,030 --> 01:14:57,260 cooperate by using a mix of CSS, but with some JavaScript code. 1615 01:14:57,260 --> 01:14:59,540 And so what Bootstrap does for you is it actually 1616 01:14:59,540 --> 01:15:01,940 automates some of the process of that JavaScript code 1617 01:15:01,940 --> 01:15:04,057 that we saw two weeks ago and just used now. 1618 01:15:04,057 --> 01:15:06,140 But it doesn't just pop up a message for the user, 1619 01:15:06,140 --> 01:15:08,098 it actually gives them more immediate feedback. 1620 01:15:08,098 --> 01:15:11,270 And almost any popular web site you visit these days gives you 1621 01:15:11,270 --> 01:15:13,280 this more immediate proximal input. 1622 01:15:13,280 --> 01:15:16,760 Generally you don't see some simple error message popping up, 1623 01:15:16,760 --> 01:15:19,940 even though that's easier to do. 1624 01:15:19,940 --> 01:15:22,420 Any questions? 1625 01:15:22,420 --> 01:15:24,530 All right, so where did that logic come from? 1626 01:15:24,530 --> 01:15:27,680 So let me go into, for instance, my template 1627 01:15:27,680 --> 01:15:30,860 file now for the form in froshim6-- 1628 01:15:30,860 --> 01:15:32,840 again, the last of these examples-- 1629 01:15:32,840 --> 01:15:34,730 and you'll notice that I did this. 1630 01:15:34,730 --> 01:15:37,520 If I scroll through this file, you'll see the same HTML 1631 01:15:37,520 --> 01:15:39,330 as we've been using for some time. 1632 01:15:39,330 --> 01:15:43,010 But notice at the bottom of the page that I draw some inspiration 1633 01:15:43,010 --> 01:15:48,290 from two weeks back when we looked at HTML, and CSS, and JavaScript. 1634 01:15:48,290 --> 01:15:51,650 So just as a quick refresher, notice how this is working. 1635 01:15:51,650 --> 01:15:54,320 This line of code says in JavaScript check 1636 01:15:54,320 --> 01:15:57,730 the document using the query selector, which lets you select anything 1637 01:15:57,730 --> 01:16:00,740 in the web page looking for a form. 1638 01:16:00,740 --> 01:16:05,840 When that form is submitted, call the following anonymous function. 1639 01:16:05,840 --> 01:16:11,210 If the document query selector finds an input that does not have a value-- 1640 01:16:11,210 --> 01:16:13,522 and I say not because of the exclamation point here-- 1641 01:16:13,522 --> 01:16:15,980 then yell at the user with this, you must provide your name 1642 01:16:15,980 --> 01:16:17,120 and return false. 1643 01:16:17,120 --> 01:16:22,820 Else if the user did not provide a value for the select menu-- a.k.a. the dorm-- 1644 01:16:22,820 --> 01:16:25,520 go ahead and alert them that they must provide the dorm, 1645 01:16:25,520 --> 01:16:26,930 otherwise return true. 1646 01:16:26,930 --> 01:16:29,270 And just to be clear and to recall from two weeks ago, 1647 01:16:29,270 --> 01:16:31,010 what am I returning false? 1648 01:16:31,010 --> 01:16:33,032 What does that effect have logically? 1649 01:16:33,032 --> 01:16:36,270 1650 01:16:36,270 --> 01:16:38,290 Yeah, say again? 1651 01:16:38,290 --> 01:16:40,330 What was that? 1652 01:16:40,330 --> 01:16:41,930 I heard a whisper here. 1653 01:16:41,930 --> 01:16:43,730 No? 1654 01:16:43,730 --> 01:16:46,312 Yeah, it prevents submission of the form. 1655 01:16:46,312 --> 01:16:48,770 The default behavior of a form is it wants to be submitted. 1656 01:16:48,770 --> 01:16:49,950 That's why they exist. 1657 01:16:49,950 --> 01:16:51,920 But if you return false in JavaScript, it 1658 01:16:51,920 --> 01:16:54,860 will short circuit that and prevent that default behavior, 1659 01:16:54,860 --> 01:16:58,050 thereby stopping the user from submitting the form at all. 1660 01:16:58,050 --> 01:17:02,810 So let's take one step back now, there's now so much going on in this one file 1661 01:17:02,810 --> 01:17:03,500 alone. 1662 01:17:03,500 --> 01:17:05,990 In this sixth and final example, notice that we 1663 01:17:05,990 --> 01:17:09,260 have application.py, which is the entry point, the so-called controller 1664 01:17:09,260 --> 01:17:11,090 of this web application. 1665 01:17:11,090 --> 01:17:15,380 It has a route which very simply for slash looks like this. 1666 01:17:15,380 --> 01:17:19,490 When the user gets slash, this template is simply returned. 1667 01:17:19,490 --> 01:17:22,320 What is in that index.html template? 1668 01:17:22,320 --> 01:17:25,560 Well, it contains a partial HTML file. 1669 01:17:25,560 --> 01:17:27,550 It contains this HTML. 1670 01:17:27,550 --> 01:17:31,160 But it does not contain the doctype, the HTML tag, head tag, the body tag, 1671 01:17:31,160 --> 01:17:32,570 the title tag, and all of that. 1672 01:17:32,570 --> 01:17:37,040 It only contains the stuff that should go inside of the body tag. 1673 01:17:37,040 --> 01:17:39,890 Because this file is using a bit of jinja, 1674 01:17:39,890 --> 01:17:42,260 which is the templating language that Flask uses. 1675 01:17:42,260 --> 01:17:44,540 You can just think of it as Flask, that's fine. 1676 01:17:44,540 --> 01:17:51,980 It uses some HTML here, but it also in the bottom of the file uses JavaScript. 1677 01:17:51,980 --> 01:17:55,880 And so just as before when we've looked at the source of the page, what 1678 01:17:55,880 --> 01:18:00,230 I'm going to see in the browser on this forms page is no jinja, 1679 01:18:00,230 --> 01:18:02,810 no Python, nothing related to Flask. 1680 01:18:02,810 --> 01:18:06,530 Just a fully formed HTML page that also now contains 1681 01:18:06,530 --> 01:18:08,480 some of that client side code. 1682 01:18:08,480 --> 01:18:11,570 And so I have this mixture now of several different language, 1683 01:18:11,570 --> 01:18:15,978 but each of which solves a very distinct problem. 1684 01:18:15,978 --> 01:18:16,952 Yeah? 1685 01:18:16,952 --> 01:18:21,010 AUDIENCE: So I think it was a week ago or two weeks ago when 1686 01:18:21,010 --> 01:18:23,039 we were working on JavaScript and CSS, you 1687 01:18:23,039 --> 01:18:28,883 were saying that it's preferable to split languages, not 1688 01:18:28,883 --> 01:18:30,588 mix them in the same document. 1689 01:18:30,588 --> 01:18:32,570 Right now we are mixing multiple languages. 1690 01:18:32,570 --> 01:18:34,111 DAVID MALAN: Really good observation. 1691 01:18:34,111 --> 01:18:37,100 So a couple of weeks ago I really preached the separation of concerns, 1692 01:18:37,100 --> 01:18:38,630 and therefore separation of files. 1693 01:18:38,630 --> 01:18:40,940 And that's why we introduced a .css file, 1694 01:18:40,940 --> 01:18:44,450 we also briefly showed examples of a .js file. 1695 01:18:44,450 --> 01:18:47,780 The short answer is as your applications get more complex, 1696 01:18:47,780 --> 01:18:48,835 life starts to get messy. 1697 01:18:48,835 --> 01:18:50,960 And the team and I were actually talking about this 1698 01:18:50,960 --> 01:18:53,210 earlier as to how to present some of these examples, 1699 01:18:53,210 --> 01:18:57,770 because what you are seeing in my design decision here is a tension. 1700 01:18:57,770 --> 01:19:00,090 So that tension here is as follows. 1701 01:19:00,090 --> 01:19:04,100 It is not necessarily the best practice to just have your logical JavaScript 1702 01:19:04,100 --> 01:19:06,794 code comingled with your HTML. 1703 01:19:06,794 --> 01:19:08,960 It makes it harder to collaborate with someone else. 1704 01:19:08,960 --> 01:19:11,900 If one of you is really good at design and wants to work on the HTML and CSS, 1705 01:19:11,900 --> 01:19:14,540 the other person really wants to do the JavaScript code, kind of hard 1706 01:19:14,540 --> 01:19:16,460 to do that when they're both in the same file. 1707 01:19:16,460 --> 01:19:17,900 So we could factor this out. 1708 01:19:17,900 --> 01:19:23,420 I could change this line, just to be super clear, to be this. 1709 01:19:23,420 --> 01:19:27,110 Instead of putting my actual code in the file, I could do something like this. 1710 01:19:27,110 --> 01:19:32,930 The source of this shall be form.js, and that is just it. 1711 01:19:32,930 --> 01:19:36,170 And then I have a separate file maybe my colleague works in as follows. 1712 01:19:36,170 --> 01:19:38,420 But at some point the thoughts that go through my head 1713 01:19:38,420 --> 01:19:42,710 are, it's only like 10 lines of code and I just 1714 01:19:42,710 --> 01:19:45,440 have to create a second file now, and that second file 1715 01:19:45,440 --> 01:19:48,230 is going to be maybe in a different folder as my template. 1716 01:19:48,230 --> 01:19:51,860 And you know, it feels like this is just overengineering a solution 1717 01:19:51,860 --> 01:19:52,740 to the problem. 1718 01:19:52,740 --> 01:19:57,420 However, once it's 20 lines, 100 lines, now OK, now it's feeling messy. 1719 01:19:57,420 --> 01:19:59,220 Somewhere there's this inflection point. 1720 01:19:59,220 --> 01:20:02,240 And this is where reasonable people will disagree, and I might argue one way, 1721 01:20:02,240 --> 01:20:03,490 you might argue the other way. 1722 01:20:03,490 --> 01:20:05,900 And honestly, both of us are probably right. 1723 01:20:05,900 --> 01:20:09,684 And so this just speaks to the web's development over time. 1724 01:20:09,684 --> 01:20:12,350 And there's fancier frameworks now. and if we tie things earlier 1725 01:20:12,350 --> 01:20:16,277 into the question about CS50 beyond, an opportunity after this class that 1726 01:20:16,277 --> 01:20:18,110 looks more closely at web programming, there 1727 01:20:18,110 --> 01:20:22,130 are even fancier frameworks nowadays than Flask and than Bootstrap 1728 01:20:22,130 --> 01:20:23,720 that if tried to solve this problem. 1729 01:20:23,720 --> 01:20:26,590 React is one of the most popular ones developed by Facebook, 1730 01:20:26,590 --> 01:20:28,340 now open source and used by so many people 1731 01:20:28,340 --> 01:20:30,710 around the world that actually addresses this issue. 1732 01:20:30,710 --> 01:20:33,530 And it allows you to separate your HTML from your CSS 1733 01:20:33,530 --> 01:20:37,820 from your JavaScript in different parts of the file but still in the same file. 1734 01:20:37,820 --> 01:20:39,500 And that was their particular solution. 1735 01:20:39,500 --> 01:20:42,749 And View and Angular, there are so many different solutions to these problems. 1736 01:20:42,749 --> 01:20:45,774 And unfortunately, once we take the training wheels of CS50 off, 1737 01:20:45,774 --> 01:20:46,940 this is what's ahead of you. 1738 01:20:46,940 --> 01:20:47,982 The world is messy. 1739 01:20:47,982 --> 01:20:50,690 And the reason there are so many darn languages and frameworks is 1740 01:20:50,690 --> 01:20:53,810 because people like you have these instincts and think, 1741 01:20:53,810 --> 01:20:55,040 this could be done better. 1742 01:20:55,040 --> 01:20:57,697 And thus do we iterate and have new and new technologies. 1743 01:20:57,697 --> 01:20:59,780 But this is the kind of stuff-- and honestly, this 1744 01:20:59,780 --> 01:21:02,370 is the kind of silliness that changes over time. 1745 01:21:02,370 --> 01:21:04,910 The fundamentals of HTTP, and client side code, 1746 01:21:04,910 --> 01:21:07,880 and JavaScript code, those fundamentals are invariant 1747 01:21:07,880 --> 01:21:10,430 even as the implementation details change. 1748 01:21:10,430 --> 01:21:12,710 So the short answer is, could this be better? 1749 01:21:12,710 --> 01:21:13,390 Probably. 1750 01:21:13,390 --> 01:21:14,390 Could it be much better? 1751 01:21:14,390 --> 01:21:15,080 I don't know. 1752 01:21:15,080 --> 01:21:18,860 It really now becomes more of a debate among developers. 1753 01:21:18,860 --> 01:21:20,000 Good question. 1754 01:21:20,000 --> 01:21:23,420 All right, so let's now use some of these basic building 1755 01:21:23,420 --> 01:21:26,330 blocks to make a final set of examples that demonstrates 1756 01:21:26,330 --> 01:21:29,739 a feature with which most of us are pretty familiar reminiscent of what we 1757 01:21:29,739 --> 01:21:31,280 did two weeks ago with Google Search. 1758 01:21:31,280 --> 01:21:32,780 At the time we searched for cats. 1759 01:21:32,780 --> 01:21:35,150 Today we'll keep it a little simpler and a little less graphical 1760 01:21:35,150 --> 01:21:36,233 and just search for words. 1761 01:21:36,233 --> 01:21:38,480 Because you'll recall from our speller problem set, 1762 01:21:38,480 --> 01:21:42,860 you implemented a spell checker with 140,000 plus English words. 1763 01:21:42,860 --> 01:21:45,770 That's a pretty juicy dataset to search over, 1764 01:21:45,770 --> 01:21:49,550 and you're probably all familiar with autocomplete these days. 1765 01:21:49,550 --> 01:21:52,370 There's hardly a website these days that when you start typing it 1766 01:21:52,370 --> 01:21:54,270 doesn't try to finish your thought for you. 1767 01:21:54,270 --> 01:21:56,450 Google, Facebook, any a number of other sites. 1768 01:21:56,450 --> 01:21:58,900 So autocomplete, how does that work? 1769 01:21:58,900 --> 01:22:00,900 Well, let me propose the following mental model. 1770 01:22:00,900 --> 01:22:03,260 If you do have some data set like a big list of words, 1771 01:22:03,260 --> 01:22:06,440 or a big list of Facebook friends, or a big list of whatever, 1772 01:22:06,440 --> 01:22:09,975 you might store that server side because it's a lot, a lot of data. 1773 01:22:09,975 --> 01:22:12,350 And in fact, next week you might store in a big database. 1774 01:22:12,350 --> 01:22:14,141 But for today we'll just store it in a file 1775 01:22:14,141 --> 01:22:15,986 like we did for the speller piece set. 1776 01:22:15,986 --> 01:22:18,110 But if you want to create an interactive experience 1777 01:22:18,110 --> 01:22:20,210 for the human, what language are you're probably 1778 01:22:20,210 --> 01:22:24,340 going to want to use so that he or she gets immediate feedback? 1779 01:22:24,340 --> 01:22:25,525 Probably JavaScript, right? 1780 01:22:25,525 --> 01:22:26,650 That's the whole principle. 1781 01:22:26,650 --> 01:22:28,810 Client side code is just going to execute faster because there's 1782 01:22:28,810 --> 01:22:30,820 no internet between you and the code. 1783 01:22:30,820 --> 01:22:33,670 But with Python, you have access to files. 1784 01:22:33,670 --> 01:22:36,850 And yet with JavaScript code you have closer access to the user, 1785 01:22:36,850 --> 01:22:38,230 so there's these tensions. 1786 01:22:38,230 --> 01:22:43,150 So how could we go about building a site that lets a human via form search 1787 01:22:43,150 --> 01:22:45,310 across that file for words? 1788 01:22:45,310 --> 01:22:47,080 Well, let's start as follows. 1789 01:22:47,080 --> 01:22:52,900 So in word 0 we have the following. 1790 01:22:52,900 --> 01:22:56,680 Large, which is just a text file borrowed from the speller problem set, 1791 01:22:56,680 --> 01:22:58,484 140,000 words, one poor line therein. 1792 01:22:58,484 --> 01:23:00,400 I'm not even going to double click and open it 1793 01:23:00,400 --> 01:23:03,280 because it's so darn big it'll take a few seconds to open. 1794 01:23:03,280 --> 01:23:06,560 In application.py we have probably the entry point to this application, 1795 01:23:06,560 --> 01:23:09,219 and in templates we have just three templates this time. 1796 01:23:09,219 --> 01:23:12,010 So just when you're reading someone else's code for the first time, 1797 01:23:12,010 --> 01:23:13,210 where should our entry point be? 1798 01:23:13,210 --> 01:23:15,710 Where should we start looking to understand what's going on? 1799 01:23:15,710 --> 01:23:18,170 1800 01:23:18,170 --> 01:23:19,235 Maybe application.py. 1801 01:23:19,235 --> 01:23:20,360 Or honestly, you know what? 1802 01:23:20,360 --> 01:23:23,030 If you want to see what something does, run it. 1803 01:23:23,030 --> 01:23:23,990 No harm in doing that. 1804 01:23:23,990 --> 01:23:25,600 So lets run Flask run. 1805 01:23:25,600 --> 01:23:26,850 Make this a little bit bigger. 1806 01:23:26,850 --> 01:23:30,020 Let me open up the URL here, open, and I see a very simple form 1807 01:23:30,020 --> 01:23:31,400 asking me for a query. 1808 01:23:31,400 --> 01:23:35,810 Let me go ahead and search for a and click Search. 1809 01:23:35,810 --> 01:23:37,970 And after a moment, OK. 1810 01:23:37,970 --> 01:23:40,730 This is a lot of words, but apparently these 1811 01:23:40,730 --> 01:23:42,860 are all the English words that our dictionary knows 1812 01:23:42,860 --> 01:23:44,480 about that start with the letter a. 1813 01:23:44,480 --> 01:23:46,354 And if I go all the way to the bottom, you'll 1814 01:23:46,354 --> 01:23:49,460 see it stops with az whatever with no B words, in fact. 1815 01:23:49,460 --> 01:23:52,290 Well, let's make sure this actually works and isn't just a trick. 1816 01:23:52,290 --> 01:23:54,320 Let's search for b words. 1817 01:23:54,320 --> 01:23:56,170 OK, so that seems to work, as well. 1818 01:23:56,170 --> 01:23:58,730 And notice I borrowed some inspiration from Google. 1819 01:23:58,730 --> 01:24:02,450 Notice that the route I'm using is called slash search like two weeks ago. 1820 01:24:02,450 --> 01:24:06,600 Does take a cue parameter for query, and b is whatever the human typed in. 1821 01:24:06,600 --> 01:24:10,010 So if I want to search for z the words, enter, 1822 01:24:10,010 --> 01:24:11,750 I should hopefully get back now z words. 1823 01:24:11,750 --> 01:24:15,650 So now unlike two weeks ago, we can implement both the front end 1824 01:24:15,650 --> 01:24:17,610 and the back end for a search engine. 1825 01:24:17,610 --> 01:24:19,910 But our search engine's searching now just for words. 1826 01:24:19,910 --> 01:24:23,150 So let's look at application.py as proposed, which is the entry point, 1827 01:24:23,150 --> 01:24:24,800 and let's see how I'm doing this. 1828 01:24:24,800 --> 01:24:28,220 So this is some code that I borrowed a little bit from last week 1829 01:24:28,220 --> 01:24:30,230 when we quickly implemented the spell checker 1830 01:24:30,230 --> 01:24:33,140 in like 12 or 20 lines of Python code. 1831 01:24:33,140 --> 01:24:35,270 I'm declaring a global variable called words, 1832 01:24:35,270 --> 01:24:38,110 and I capitalized it just to be reminiscent of last time 1833 01:24:38,110 --> 01:24:39,160 and the problem set. 1834 01:24:39,160 --> 01:24:41,240 I'm using this syntax which I alluded to earlier 1835 01:24:41,240 --> 01:24:43,700 is just more conventional or Pythonic. 1836 01:24:43,700 --> 01:24:47,540 Open the large file in Read mode and call the variable file. 1837 01:24:47,540 --> 01:24:50,240 Then here is a for loop via which you can iterate over 1838 01:24:50,240 --> 01:24:53,330 every line in the file, reading one at a time. 1839 01:24:53,330 --> 01:24:55,670 But recall, what does every line in this file end with? 1840 01:24:55,670 --> 01:24:58,270 1841 01:24:58,270 --> 01:25:01,820 Like a backslash n, and we don't really want those as part of the words. 1842 01:25:01,820 --> 01:25:03,320 That's not part of the English word. 1843 01:25:03,320 --> 01:25:07,290 So R strip, right strip removes any whitespace from the end of the string. 1844 01:25:07,290 --> 01:25:09,330 And that's why I needed to add that extra line. 1845 01:25:09,330 --> 01:25:11,750 So I'm just cleaning up the file or massaging the data 1846 01:25:11,750 --> 01:25:15,300 as you might do with any sort of data based application. 1847 01:25:15,300 --> 01:25:18,320 So then I just seem to have this route that renders the template. 1848 01:25:18,320 --> 01:25:21,440 If I look in index.html, let's follow the bread crumbs. 1849 01:25:21,440 --> 01:25:23,120 Go into index.html. 1850 01:25:23,120 --> 01:25:24,830 OK, not that much going on here. 1851 01:25:24,830 --> 01:25:27,830 Looks like an HTML form, the action of which is slash search, 1852 01:25:27,830 --> 01:25:28,850 just like Google's. 1853 01:25:28,850 --> 01:25:31,184 The method of which is is get just like Google's. 1854 01:25:31,184 --> 01:25:34,100 There's nothing really private about the words I'm searching for here, 1855 01:25:34,100 --> 01:25:35,390 so I don't care. 1856 01:25:35,390 --> 01:25:37,010 There's some fancier features here. 1857 01:25:37,010 --> 01:25:39,840 Notice placeholder is the grayed out text the human sees. 1858 01:25:39,840 --> 01:25:41,090 Auto focus. 1859 01:25:41,090 --> 01:25:42,992 What does this do again? 1860 01:25:42,992 --> 01:25:45,075 This is just a UI feature, better user experience. 1861 01:25:45,075 --> 01:25:47,290 AUDIENCE: Puts the like, right in the text box. 1862 01:25:47,290 --> 01:25:50,210 DAVID MALAN: Yeah, it puts the cursor right in the text box. 1863 01:25:50,210 --> 01:25:53,040 To focus on something in a web page means make it what's 1864 01:25:53,040 --> 01:25:54,590 interacting with the user right now. 1865 01:25:54,590 --> 01:25:56,716 And Mac OS, for instance, highlights it in blue. 1866 01:25:56,716 --> 01:25:58,590 So when you first load the page, the cursoe's 1867 01:25:58,590 --> 01:26:02,160 blinking in the choice of text boxes that you care about most. 1868 01:26:02,160 --> 01:26:05,625 Autocomplete off just disables the browser's version of autocomplete. 1869 01:26:05,625 --> 01:26:08,250 So I don't see past searches, just because the whole point here 1870 01:26:08,250 --> 01:26:10,440 is to implement this ourselves ultimately, 1871 01:26:10,440 --> 01:26:11,820 and then I have my search button. 1872 01:26:11,820 --> 01:26:15,360 This is just jinja stuff from Flask so that I have a layout file. 1873 01:26:15,360 --> 01:26:16,730 Lets follow that breadcrumb. 1874 01:26:16,730 --> 01:26:20,250 Lay out.html, nothing really that interesting going on there. 1875 01:26:20,250 --> 01:26:23,010 If you've ever wondered why we have these in a lot of our demos, 1876 01:26:23,010 --> 01:26:26,130 this cryptic looking line here just makes web sites look better 1877 01:26:26,130 --> 01:26:27,600 on mobile devices. 1878 01:26:27,600 --> 01:26:30,750 Typically by default if you pull up your phone and look at a website, 1879 01:26:30,750 --> 01:26:32,700 if it doesn't have that kind of line, like 1880 01:26:32,700 --> 01:26:35,970 the text is going to be super tiny unless you pinch and zoom. 1881 01:26:35,970 --> 01:26:38,460 By using this line and variations thereof, 1882 01:26:38,460 --> 01:26:40,320 it will increase the default font size a bit 1883 01:26:40,320 --> 01:26:42,540 to make it a little more tolerable on small screen. 1884 01:26:42,540 --> 01:26:44,970 So it's an easy win for users experience. 1885 01:26:44,970 --> 01:26:48,420 OK, I seem to have exhausted all the interesting stuff in these templates. 1886 01:26:48,420 --> 01:26:50,740 Let's look at another and final route. 1887 01:26:50,740 --> 01:26:55,410 Here's my search route, and this is pretty Pythonic. 1888 01:26:55,410 --> 01:26:57,510 This is a mouthful, and will re-implement it 1889 01:26:57,510 --> 01:26:59,260 in a different way in just a moment. 1890 01:26:59,260 --> 01:27:02,880 So I have a search route that listens for get requests on slash search. 1891 01:27:02,880 --> 01:27:07,029 Then this crazy looking line is about as Pythonic as code gets. 1892 01:27:07,029 --> 01:27:08,820 And I'll explain what this is doing and why 1893 01:27:08,820 --> 01:27:14,130 it's conventional as opposed to straightforward at first glance. 1894 01:27:14,130 --> 01:27:17,010 And then I render the template, passing in these words. 1895 01:27:17,010 --> 01:27:20,610 So this one liner on line 17 actually has the effect 1896 01:27:20,610 --> 01:27:23,910 of searching 140,000 words for whatever words 1897 01:27:23,910 --> 01:27:26,110 start with what the user typed in. 1898 01:27:26,110 --> 01:27:28,440 See, this would be a pain in the neck to do. 1899 01:27:28,440 --> 01:27:30,620 In Python you can do it with literally one line. 1900 01:27:30,620 --> 01:27:33,120 A long line, but one line nonetheless. 1901 01:27:33,120 --> 01:27:34,650 Let me make this more clear. 1902 01:27:34,650 --> 01:27:38,579 If I were to search for words in this big file, 1903 01:27:38,579 --> 01:27:39,870 I might do something like this. 1904 01:27:39,870 --> 01:27:41,150 Words is an empty list. 1905 01:27:41,150 --> 01:27:43,679 So this lower case words is all of the words that match, 1906 01:27:43,679 --> 01:27:45,220 that I want to send back to the user. 1907 01:27:45,220 --> 01:27:47,520 So by default I have no idea what to send back. 1908 01:27:47,520 --> 01:27:48,960 But I do know I can do this. 1909 01:27:48,960 --> 01:27:50,640 For word in Words-- 1910 01:27:50,640 --> 01:27:53,630 which is the capitalized variable, the constant up at the top 1911 01:27:53,630 --> 01:27:55,380 that has the whole-- or not even constant, 1912 01:27:55,380 --> 01:27:58,760 but the global variable that has all of the words from the file, here 1913 01:27:58,760 --> 01:28:00,420 is a for loop over those. 1914 01:28:00,420 --> 01:28:02,290 I can now say something like this. 1915 01:28:02,290 --> 01:28:07,110 If the current word starts with whatever the user typed in-- well, 1916 01:28:07,110 --> 01:28:08,340 what's the user typing in? 1917 01:28:08,340 --> 01:28:13,080 Well, q equals request.args.get quote-unquote q, 1918 01:28:13,080 --> 01:28:17,790 gives me the user's name, dorm, or in this case Q value for query. 1919 01:28:17,790 --> 01:28:22,410 So if the word that we're currently iterating over starts with q, 1920 01:28:22,410 --> 01:28:33,350 I can go ahead and append to my-- whoops, append to this list that word. 1921 01:28:33,350 --> 01:28:35,880 Would you say you're comfortable with these lines here? 1922 01:28:35,880 --> 01:28:41,070 To recap, give me an empty list in which to store the search results, 1923 01:28:41,070 --> 01:28:44,650 iterate over all possible 140,000 plus words, get-- 1924 01:28:44,650 --> 01:28:45,900 and actually, this was stupid. 1925 01:28:45,900 --> 01:28:49,050 I should just put this up here, because I only need to check for that once. 1926 01:28:49,050 --> 01:28:52,290 So store the user's input in a variable called q. 1927 01:28:52,290 --> 01:28:57,420 For each word among the 140,000, check if it starts with the user's input-- 1928 01:28:57,420 --> 01:28:59,190 a, b, z, whatever. 1929 01:28:59,190 --> 01:29:02,100 And if so, append it to there. 1930 01:29:02,100 --> 01:29:05,190 So let's temporarily get rid of this and just render the template. 1931 01:29:05,190 --> 01:29:09,210 So notice this gets the job done, but this is very C-like logic. 1932 01:29:09,210 --> 01:29:11,370 It's not wrong, it's perfectly correct. 1933 01:29:11,370 --> 01:29:14,460 But Python is a language that's meant to be 1934 01:29:14,460 --> 01:29:17,340 a little more human readable and a little more elegant, 1935 01:29:17,340 --> 01:29:19,050 if a little more non-obvious. 1936 01:29:19,050 --> 01:29:21,270 So this one line does the exact same thing 1937 01:29:21,270 --> 01:29:24,530 using a feature called a list comprehension, which 1938 01:29:24,530 --> 01:29:27,330 is ironic if you don't quite comprehend how it's working. 1939 01:29:27,330 --> 01:29:30,080 But here's the variable I want to create called Words. 1940 01:29:30,080 --> 01:29:33,169 These square brackets here say give me a list. 1941 01:29:33,169 --> 01:29:34,710 What do you want to put in that list? 1942 01:29:34,710 --> 01:29:36,339 I want to put a word in this list. 1943 01:29:36,339 --> 01:29:38,130 Which word do you want to put in this list? 1944 01:29:38,130 --> 01:29:42,960 The result of inducing this loop and then only putting in this list 1945 01:29:42,960 --> 01:29:46,577 a word if it starts with what the human typed in. 1946 01:29:46,577 --> 01:29:48,660 So it takes some getting used to, but this is just 1947 01:29:48,660 --> 01:29:53,160 a one liner way, a very Pythonic way of expressing those several lines of very 1948 01:29:53,160 --> 01:29:56,130 procedural code into a simple one line. 1949 01:29:56,130 --> 01:29:57,450 Is it better? 1950 01:29:57,450 --> 01:29:58,492 Not if you can't read it. 1951 01:29:58,492 --> 01:30:00,408 But once you get more comfortable with Python, 1952 01:30:00,408 --> 01:30:02,220 yes, it's better because it's less code. 1953 01:30:02,220 --> 01:30:02,925 Yeah? 1954 01:30:02,925 --> 01:30:07,875 AUDIENCE: You said Python uses notation to tell where conditions are. 1955 01:30:07,875 --> 01:30:09,425 How is [INAUDIBLE]? 1956 01:30:09,425 --> 01:30:10,550 DAVID MALAN: Good question. 1957 01:30:10,550 --> 01:30:13,700 In this case of a list comprehension, you can only 1958 01:30:13,700 --> 01:30:16,610 have one line or one condition. 1959 01:30:16,610 --> 01:30:19,809 You can't have multiple lines therein, so I cannot start hitting Enter 1960 01:30:19,809 --> 01:30:20,600 and indenting here. 1961 01:30:20,600 --> 01:30:21,890 It's just not allowed. 1962 01:30:21,890 --> 01:30:24,950 So you would only use this-- and I'm frankly really pushing the limits. 1963 01:30:24,950 --> 01:30:27,950 You should only really use this syntax when it fits on your screen 1964 01:30:27,950 --> 01:30:30,200 or fits on a reasonable person's screen. 1965 01:30:30,200 --> 01:30:33,530 After that you should probably do something a little more expressive. 1966 01:30:33,530 --> 01:30:35,277 Other questions? 1967 01:30:35,277 --> 01:30:36,860 But this is very common to see online. 1968 01:30:36,860 --> 01:30:39,380 So any tutorials, if you ever see this kind of one liner, 1969 01:30:39,380 --> 01:30:43,460 just try to think about it from that approach what it is actually doing. 1970 01:30:43,460 --> 01:30:46,820 OK, so propose from a user experience perspective 1971 01:30:46,820 --> 01:30:48,320 how could this program be better? 1972 01:30:48,320 --> 01:30:50,070 Because this is just our first version. 1973 01:30:50,070 --> 01:30:53,780 So what could be better for the user than this? 1974 01:30:53,780 --> 01:30:57,630 1975 01:30:57,630 --> 01:30:59,180 What could be better? 1976 01:30:59,180 --> 01:31:00,788 Yeah? 1977 01:31:00,788 --> 01:31:06,514 AUDIENCE: Just going back, can you explain words in caps? 1978 01:31:06,514 --> 01:31:07,430 DAVID MALAN: Oh, sure. 1979 01:31:07,430 --> 01:31:13,670 Words in caps is this global variable I defined up here that stores all 140,000 1980 01:31:13,670 --> 01:31:14,450 plus words. 1981 01:31:14,450 --> 01:31:17,900 That's the really big file called large, the text file. 1982 01:31:17,900 --> 01:31:20,000 Down here I just need a local variable. 1983 01:31:20,000 --> 01:31:23,030 And if it's more clear, I could call it results and then just 1984 01:31:23,030 --> 01:31:24,590 say results equals results. 1985 01:31:24,590 --> 01:31:28,370 That is the subset of words that start with a, or b, 1986 01:31:28,370 --> 01:31:30,780 or whatever the human typed in. 1987 01:31:30,780 --> 01:31:31,870 That's all. 1988 01:31:31,870 --> 01:31:32,480 Good question. 1989 01:31:32,480 --> 01:31:32,690 Yeah? 1990 01:31:32,690 --> 01:31:34,640 AUDIENCE: Why do we change the last time-- why 1991 01:31:34,640 --> 01:31:37,467 did you have to change args to form? 1992 01:31:37,467 --> 01:31:39,550 DAVID MALAN: Why did I have to change my args to-- 1993 01:31:39,550 --> 01:31:41,590 AUDIENCE: Forms? 1994 01:31:41,590 --> 01:31:45,940 DAVID MALAN: So earlier today when I didn't understand what was going on, 1995 01:31:45,940 --> 01:31:49,090 you should use request.args for get requests. 1996 01:31:49,090 --> 01:31:52,445 You should use request.form for post requests. 1997 01:31:52,445 --> 01:31:55,060 AUDIENCE: But it's still .get after? 1998 01:31:55,060 --> 01:31:57,040 DAVID MALAN: It's always .get, yes. 1999 01:31:57,040 --> 01:31:59,260 But you change what you're getting things from. 2000 01:31:59,260 --> 01:32:03,730 In an ideal world, it would have been something-- oh, I see what you mean. 2001 01:32:03,730 --> 01:32:05,950 Get in this sense is the verb. 2002 01:32:05,950 --> 01:32:08,960 We humans mean go get something. 2003 01:32:08,960 --> 01:32:11,910 Args in this sense, if they had done get-- 2004 01:32:11,910 --> 01:32:14,410 I'm making this up, but this is probably why they did this. 2005 01:32:14,410 --> 01:32:18,460 Because get from get seems weird, whereas get from post is less weird. 2006 01:32:18,460 --> 01:32:21,840 But it's just they called it args and form instead. 2007 01:32:21,840 --> 01:32:24,714 OK, so let's actually improve this, but how? 2008 01:32:24,714 --> 01:32:26,130 What could be better for the user? 2009 01:32:26,130 --> 01:32:26,600 Yeah? 2010 01:32:26,600 --> 01:32:28,390 AUDIENCE: They could search a word, not just the first letter. 2011 01:32:28,390 --> 01:32:29,980 DAVID MALAN: OK, maybe searching a whole word 2012 01:32:29,980 --> 01:32:31,688 would be good, not just the first letter. 2013 01:32:31,688 --> 01:32:33,264 What else could we do? 2014 01:32:33,264 --> 01:32:38,882 AUDIENCE: We can create an index list of letters and words? 2015 01:32:38,882 --> 01:32:40,840 DAVID MALAN: OK, we could create an index list. 2016 01:32:40,840 --> 01:32:45,016 So maybe using a hash or some form of inspiration from our problem 2017 01:32:45,016 --> 01:32:47,890 set with Speller and actually use a more sophisticated data structure 2018 01:32:47,890 --> 01:32:49,872 to get these answers more quickly. 2019 01:32:49,872 --> 01:32:53,080 And let me propose, too, the goal here is to actually implement autocomplete, 2020 01:32:53,080 --> 01:32:54,380 and this was not auto complete. 2021 01:32:54,380 --> 01:32:56,020 This was like old school search. 2022 01:32:56,020 --> 01:32:58,720 Type in a query, hit Enter, get a page of results. 2023 01:32:58,720 --> 01:33:00,760 What if we want to do something more immediate? 2024 01:33:00,760 --> 01:33:02,350 So let me actually propose this. 2025 01:33:02,350 --> 01:33:05,140 Before looking at the code, let me go into words 1. 2026 01:33:05,140 --> 01:33:07,662 Let me go ahead and run Flask in that directory. 2027 01:33:07,662 --> 01:33:09,370 Let me go ahead and reload the form here, 2028 01:33:09,370 --> 01:33:12,040 and now notice no Submit button because there's not going 2029 01:33:12,040 --> 01:33:13,960 to be any actual submissions here. 2030 01:33:13,960 --> 01:33:18,220 But I'm going to go ahead and hit the letter A, and ooh, that's kind of cool. 2031 01:33:18,220 --> 01:33:20,140 Let me delete that, goes away. 2032 01:33:20,140 --> 01:33:22,120 B, there's all the B words. 2033 01:33:22,120 --> 01:33:28,420 Let me go B-A words, B-A-B words, B-A-B-A words. 2034 01:33:28,420 --> 01:33:31,450 This is how autocomplete works. 2035 01:33:31,450 --> 01:33:35,800 So it seems to be responding immediately to my input, so something's happening. 2036 01:33:35,800 --> 01:33:37,630 But I'm not actually submitting the form. 2037 01:33:37,630 --> 01:33:40,900 So I'm kind of using it now, it seems client side JavaScript 2038 01:33:40,900 --> 01:33:42,340 to maybe talk to the server? 2039 01:33:42,340 --> 01:33:42,919 Let's infer. 2040 01:33:42,919 --> 01:33:44,710 So here, too, this should be your instinct. 2041 01:33:44,710 --> 01:33:47,418 Whenever you're trying to understand how someone's website works, 2042 01:33:47,418 --> 01:33:50,710 if you want to learn from it or mimic certain fundamental functionality, 2043 01:33:50,710 --> 01:33:52,810 go ahead and inspect the page. 2044 01:33:52,810 --> 01:33:55,690 And you don't probably care too much about the HTML yet. 2045 01:33:55,690 --> 01:33:57,130 Where is this data coming from? 2046 01:33:57,130 --> 01:34:00,644 Let me click on the Network tab, which we looked at a couple of weeks ago. 2047 01:34:00,644 --> 01:34:03,310 Let me go ahead and restart this and let me clear this and start 2048 01:34:03,310 --> 01:34:04,660 from the beginning of the story. 2049 01:34:04,660 --> 01:34:08,590 Let's see what happens when I type the letter A. Interesting. 2050 01:34:08,590 --> 01:34:10,580 There is a web request. 2051 01:34:10,580 --> 01:34:14,830 So if I zoom in down here, notice that my browser actually searched 2052 01:34:14,830 --> 01:34:17,254 for Q equals A, the human's input. 2053 01:34:17,254 --> 01:34:19,420 Let me go ahead and-- it keeps searching because I'm 2054 01:34:19,420 --> 01:34:20,670 using keyboard shortcuts here. 2055 01:34:20,670 --> 01:34:22,900 But let me go ahead and click this row. 2056 01:34:22,900 --> 01:34:24,190 Notice what happened. 2057 01:34:24,190 --> 01:34:29,980 I made a request to slash search question mark q equals a via get. 2058 01:34:29,980 --> 01:34:31,600 Let's see what the response was. 2059 01:34:31,600 --> 01:34:34,000 The response here, if I view the source-- 2060 01:34:34,000 --> 01:34:37,360 or rather, if I read the response-- 2061 01:34:37,360 --> 01:34:38,800 notice what came back. 2062 01:34:38,800 --> 01:34:44,050 It looks like my server returned to me a fragment of HTML containing hundreds, 2063 01:34:44,050 --> 01:34:47,980 maybe thousands of words starting with A. But notice there's no UL tag, 2064 01:34:47,980 --> 01:34:51,430 there's no head tag, no title, no body, it's just a partial HTML fragment. 2065 01:34:51,430 --> 01:34:54,710 But that's interesting, because I know with Python I can do exactly that. 2066 01:34:54,710 --> 01:34:57,430 I can generate anything I want on the server, 2067 01:34:57,430 --> 01:35:01,400 and then maybe the browser can just plug in those changed the results. 2068 01:35:01,400 --> 01:35:03,710 So let me go ahead and look at the code for this page. 2069 01:35:03,710 --> 01:35:08,290 If I go now to the browser's source code, the view page source, 2070 01:35:08,290 --> 01:35:10,570 you'll see a few new lines. 2071 01:35:10,570 --> 01:35:14,420 So to do this easily, I'm actually using another library. 2072 01:35:14,420 --> 01:35:15,970 This one is called jQuery. 2073 01:35:15,970 --> 01:35:18,019 This was for many years super, super popular. 2074 01:35:18,019 --> 01:35:19,810 It's kind of starting to fall out of vogue, 2075 01:35:19,810 --> 01:35:21,970 but it's still so powerful and so useful. 2076 01:35:21,970 --> 01:35:25,160 And it's used by Bootstrap, the other CSS library we've talked about, 2077 01:35:25,160 --> 01:35:28,190 so it's perfectly reasonable to use it here. 2078 01:35:28,190 --> 01:35:30,340 Notice how I'm including it with the script tag, 2079 01:35:30,340 --> 01:35:32,380 and it's hosted on a third party website so 2080 01:35:32,380 --> 01:35:35,980 that I don't have to save a copy of it myself on my own IDE. 2081 01:35:35,980 --> 01:35:38,110 Then let's look at the code I actually wrote. 2082 01:35:38,110 --> 01:35:41,800 So notice that atop this file is not even a full fledged form, 2083 01:35:41,800 --> 01:35:43,305 it is just the HTML input. 2084 01:35:43,305 --> 01:35:44,680 Because I don't need a full form. 2085 01:35:44,680 --> 01:35:46,596 I don't need an action, I don't need a method, 2086 01:35:46,596 --> 01:35:50,080 because I'm not submitting it anywhere with the human's cooperation. 2087 01:35:50,080 --> 01:35:51,700 I'm going to use my own code. 2088 01:35:51,700 --> 01:35:55,870 So in my script tag here, my JavaScript code, notice what I'm doing. 2089 01:35:55,870 --> 01:35:57,880 This is some code from like two weeks ago. 2090 01:35:57,880 --> 01:36:01,060 I'm going to search the tree that represents this web page. 2091 01:36:01,060 --> 01:36:02,650 And indeed, it is meant to be a tree. 2092 01:36:02,650 --> 01:36:05,890 Recall from that time when we looked at an HTML page, 2093 01:36:05,890 --> 01:36:09,550 there is in memory, thanks to the browser, something treelike-- 2094 01:36:09,550 --> 01:36:12,460 a DOM, document object model-- that represents your page. 2095 01:36:12,460 --> 01:36:16,940 Using JavaScript, can we change that page after the fact? 2096 01:36:16,940 --> 01:36:18,590 So what am I going to do? 2097 01:36:18,590 --> 01:36:23,620 I'm going to tell the browser whenever this input hears an event called on key 2098 01:36:23,620 --> 01:36:27,490 up-- so whenever the field has focus-- it's blue in Mac OS-- 2099 01:36:27,490 --> 01:36:30,190 and the human hits the key and then let's go, 2100 01:36:30,190 --> 01:36:34,550 and the key goes up, go ahead and call the following anonymous function. 2101 01:36:34,550 --> 01:36:35,749 What do you want that to do? 2102 01:36:35,749 --> 01:36:37,540 Now, this code is a little cryptic, but let 2103 01:36:37,540 --> 01:36:40,660 me walk us through it because it's only three lines. 2104 01:36:40,660 --> 01:36:44,410 This code here is using a special feature-- 2105 01:36:44,410 --> 01:36:47,350 dollar sign-- that comes from this library called jQuery. 2106 01:36:47,350 --> 01:36:48,670 More on that in a moment. 2107 01:36:48,670 --> 01:36:54,520 That library, somewhat confusingly named, has a function called get, 2108 01:36:54,520 --> 01:36:57,530 which has nothing to do with Python or the one we just talked about. 2109 01:36:57,530 --> 01:36:59,980 But this has to do with an HTTP get. 2110 01:36:59,980 --> 01:37:02,200 With this line of code, you can tell a browser, 2111 01:37:02,200 --> 01:37:06,940 even after a web page has been loaded, go get me this other URL, please. 2112 01:37:06,940 --> 01:37:08,620 So what URL do you want to get? 2113 01:37:08,620 --> 01:37:13,900 Go ahead and get me from the same server slash search q equals, 2114 01:37:13,900 --> 01:37:17,400 and then what does plus mean in JavaScript if you recall? 2115 01:37:17,400 --> 01:37:18,260 Concatenation. 2116 01:37:18,260 --> 01:37:20,629 So it means just append one string to the other. 2117 01:37:20,629 --> 01:37:22,420 So this is like saying, go ahead and get me 2118 01:37:22,420 --> 01:37:27,870 the URL that ends with slash search, question mark, Q equals A, or Q equals 2119 01:37:27,870 --> 01:37:31,140 B, or Q equals Z. Whatever the human typed and just gets 2120 01:37:31,140 --> 01:37:32,607 slapped onto the end. 2121 01:37:32,607 --> 01:37:34,440 And then that's where we're getting it from. 2122 01:37:34,440 --> 01:37:37,770 Input.value is the user's input, the value thereof. 2123 01:37:37,770 --> 01:37:40,790 And then the last line-- and this is perhaps the fanciest-- 2124 01:37:40,790 --> 01:37:43,680 notice that I have an anonymous function. 2125 01:37:43,680 --> 01:37:47,010 In this library called jQuery, there is this function 2126 01:37:47,010 --> 01:37:49,590 called get that gets a URL. 2127 01:37:49,590 --> 01:37:54,570 When the server responds to your request with a virtual envelope of its own, 2128 01:37:54,570 --> 01:37:57,420 this anonymous function gets called and the response envelope 2129 01:37:57,420 --> 01:38:03,480 gets handed to you, so to speak, as a data argument, as a data variable. 2130 01:38:03,480 --> 01:38:05,070 Then what you can you do? 2131 01:38:05,070 --> 01:38:07,530 Document.queryselector UL. 2132 01:38:07,530 --> 01:38:08,220 What is UL? 2133 01:38:08,220 --> 01:38:11,790 It's an unordered list that by default on this page has nothing in it. 2134 01:38:11,790 --> 01:38:15,150 But recall that what the server is sending back is a bunch of LI tags. 2135 01:38:15,150 --> 01:38:18,160 That's great, because I want to put those LI tags right in between here. 2136 01:38:18,160 --> 01:38:19,300 So how do I do that? 2137 01:38:19,300 --> 01:38:21,614 I go into the so-called inner HTML of the UL tag, 2138 01:38:21,614 --> 01:38:23,280 and you might not have seen this before. 2139 01:38:23,280 --> 01:38:28,110 But you can change the contents of an existing tag inside of it 2140 01:38:28,110 --> 01:38:31,980 by using inner HTML and just plop the data in there. 2141 01:38:31,980 --> 01:38:34,090 And so what's happening is this. 2142 01:38:34,090 --> 01:38:36,360 Let me go ahead and open up Chrome's inspector. 2143 01:38:36,360 --> 01:38:37,920 Reload the page so it's empty. 2144 01:38:37,920 --> 01:38:40,080 Let me open up Chrome's inspector. 2145 01:38:40,080 --> 01:38:43,980 Go to elements, as is the default. And notice on this page, 2146 01:38:43,980 --> 01:38:48,300 notice that UL tag is opened and closed with nothing inside of it. 2147 01:38:48,300 --> 01:38:51,660 The moment, though, I search for something, watch what happens. 2148 01:38:51,660 --> 01:38:54,420 If I search for a, all of a sudden-- 2149 01:38:54,420 --> 01:38:56,550 ooh, it blinked, it's a little small. 2150 01:38:56,550 --> 01:38:58,050 Now there's a little triangle there. 2151 01:38:58,050 --> 01:38:59,550 What's inside of it? 2152 01:38:59,550 --> 01:39:03,130 All of those LI tags that came from the server. 2153 01:39:03,130 --> 01:39:05,940 So with JavaScript, we have this amazing power now 2154 01:39:05,940 --> 01:39:10,101 to change what's inside of a web page by just asking the server for more data. 2155 01:39:10,101 --> 01:39:11,850 So if you've ever used Facebook, or you've 2156 01:39:11,850 --> 01:39:15,154 used Google Chat, or any websites that's dynamically changing every second, 2157 01:39:15,154 --> 01:39:17,820 every minute and each time you get a message, you can literally, 2158 01:39:17,820 --> 01:39:21,435 if you get a little nosy, open up Chrome's inspector and watch the DOM, 2159 01:39:21,435 --> 01:39:23,070 watch this elements tab. 2160 01:39:23,070 --> 01:39:25,440 And you'll see new stuff popping up every time 2161 01:39:25,440 --> 01:39:29,460 you get a message, or a chat, or any other such notification on the screen. 2162 01:39:29,460 --> 01:39:32,884 Now as an aside, this is a little sloppy to be returning HTML, 2163 01:39:32,884 --> 01:39:34,050 but let's see how it's done. 2164 01:39:34,050 --> 01:39:39,450 Let me go into application.py for words one, which is this example here. 2165 01:39:39,450 --> 01:39:43,110 And in application.py, notice what I'm doing is this. 2166 01:39:43,110 --> 01:39:46,800 Rather than return a whole page of results, 2167 01:39:46,800 --> 01:39:49,590 I'm returning a template called search.html. 2168 01:39:49,590 --> 01:39:52,600 All of the rest of this code is identical to before. 2169 01:39:52,600 --> 01:39:57,600 If I go into my templates and go into search.html, look how terribly simple 2170 01:39:57,600 --> 01:39:59,040 the code is on the server. 2171 01:39:59,040 --> 01:40:02,010 If all you want to do is spit out a bunch of list items, 2172 01:40:02,010 --> 01:40:02,890 this is all you need. 2173 01:40:02,890 --> 01:40:03,570 There's no template. 2174 01:40:03,570 --> 01:40:06,778 Like there's no extends layout because you're not returning a whole web page, 2175 01:40:06,778 --> 01:40:11,430 you're returning a tiny, tiny, tiny fragment of HTML. 2176 01:40:11,430 --> 01:40:14,490 But this is arguably a little sloppy, because there's 2177 01:40:14,490 --> 01:40:16,530 a lot of redundancy in what's coming back. 2178 01:40:16,530 --> 01:40:19,202 If I look at this tag that's coming back from the server, 2179 01:40:19,202 --> 01:40:22,410 what is obviously redundant about all of this information that's coming back? 2180 01:40:22,410 --> 01:40:25,540 And if I look at the Network tab, you really see it under response. 2181 01:40:25,540 --> 01:40:26,573 What's redundant? 2182 01:40:26,573 --> 01:40:29,807 AUDIENCE: You're doing a bunch of calls to the same address and to the same-- 2183 01:40:29,807 --> 01:40:32,890 DAVID MALAN: This was just because I hit some, like, zoom in and zoom out, 2184 01:40:32,890 --> 01:40:34,640 so it pretended to make multiple requests. 2185 01:40:34,640 --> 01:40:35,830 So red herring there. 2186 01:40:35,830 --> 01:40:37,720 Focus only on this part here. 2187 01:40:37,720 --> 01:40:41,240 What's redundant about all of the data coming back? 2188 01:40:41,240 --> 01:40:43,840 It's just keeps saying list item, word, close list item. 2189 01:40:43,840 --> 01:40:45,640 List item, word, clothes list item. 2190 01:40:45,640 --> 01:40:48,400 I mean come on, just use a more efficient syntax. 2191 01:40:48,400 --> 01:40:51,620 Just separate things with commas or something lighter weight. 2192 01:40:51,620 --> 01:40:53,140 This is sending way many bytes. 2193 01:40:53,140 --> 01:40:53,740 I mean, look. 2194 01:40:53,740 --> 01:40:55,480 There's thousands of bytes. 2195 01:40:55,480 --> 01:40:58,630 This is kilobytes by definition of information 2196 01:40:58,630 --> 01:41:00,630 that we're sending just to send open bracket, 2197 01:41:00,630 --> 01:41:02,200 LI close bracket again and again. 2198 01:41:02,200 --> 01:41:03,410 This is not very efficient. 2199 01:41:03,410 --> 01:41:06,430 And so the world actually has adopted a different approach, 2200 01:41:06,430 --> 01:41:10,600 and I'm going to show this in words 2 that actually returns something called 2201 01:41:10,600 --> 01:41:15,040 JavaScript Object Notation, which is a more succinct representation of this 2202 01:41:15,040 --> 01:41:15,710 as follows. 2203 01:41:15,710 --> 01:41:20,470 Let me go into words 2, run Flask in there. 2204 01:41:20,470 --> 01:41:22,754 Search for the same kind of thing and then watch 2205 01:41:22,754 --> 01:41:24,670 what happens over the network panel this time. 2206 01:41:24,670 --> 01:41:28,520 When I search for A, immediately get back the same visual result. 2207 01:41:28,520 --> 01:41:31,780 But if I look at this search query, now look what comes back. 2208 01:41:31,780 --> 01:41:35,247 I claim that this is a much more compact representation of the same information. 2209 01:41:35,247 --> 01:41:37,330 It's a little annoying that there's double quotes, 2210 01:41:37,330 --> 01:41:38,410 because those are a little redundant. 2211 01:41:38,410 --> 01:41:40,534 But at least double quotes are a lot more efficient 2212 01:41:40,534 --> 01:41:43,670 than open bracket, LI, closed bracket, and then the opposite at the end. 2213 01:41:43,670 --> 01:41:46,300 So this is what's called JavaScript Object Notation. 2214 01:41:46,300 --> 01:41:49,420 And as this square bracket here and thousands 2215 01:41:49,420 --> 01:41:52,420 of words later the square bracket on the end implies, 2216 01:41:52,420 --> 01:41:57,110 this is a JavaScript array that's being sent back from the server. 2217 01:41:57,110 --> 01:41:59,720 So the only thing that's changed here is as follows. 2218 01:41:59,720 --> 01:42:04,150 In words 2, this example, notice that I don't even 2219 01:42:04,150 --> 01:42:06,610 need to return a template anymore. 2220 01:42:06,610 --> 01:42:08,570 This code is the same as the past two examples. 2221 01:42:08,570 --> 01:42:11,410 This is how I'm searching 140,000 words quickly. 2222 01:42:11,410 --> 01:42:16,590 But if I include now a fancier function from Flask called jsonify-- 2223 01:42:16,590 --> 01:42:17,920 which is not really a word. 2224 01:42:17,920 --> 01:42:20,920 But jsonify, that takes any data structure 2225 01:42:20,920 --> 01:42:24,520 you have data in like this list of words, the matches, 2226 01:42:24,520 --> 01:42:28,162 and it turns it into that text based representation with quotes and commas. 2227 01:42:28,162 --> 01:42:30,370 And you don't even have to write a template yourself. 2228 01:42:30,370 --> 01:42:33,070 And indeed, I got rid of search.html. 2229 01:42:33,070 --> 01:42:35,950 The only thing you have to do to give yourself access to this feature 2230 01:42:35,950 --> 01:42:39,430 is import not just render template, and request, 2231 01:42:39,430 --> 01:42:44,790 and Flask, but jsonify, as well, from the Flask library. 2232 01:42:44,790 --> 01:42:47,400 Which is just one more feature. 2233 01:42:47,400 --> 01:42:53,030 Any questions on that before we bring it all together with one final example? 2234 01:42:53,030 --> 01:42:53,683 Yeah? 2235 01:42:53,683 --> 01:42:57,140 AUDIENCE: Can double quotes break that into [INAUDIBLE]?? 2236 01:42:57,140 --> 01:42:59,330 DAVID MALAN: Can double quotes break that? 2237 01:42:59,330 --> 01:43:00,980 Good question, great instincts. 2238 01:43:00,980 --> 01:43:04,700 No because the author of jsonify was smart about this. 2239 01:43:04,700 --> 01:43:09,710 And if that author notices a quote like an apostrophe, or like something 2240 01:43:09,710 --> 01:43:14,270 in your own name that has a quote, it will escape it in some way, 2241 01:43:14,270 --> 01:43:15,500 usually with a backslash. 2242 01:43:15,500 --> 01:43:16,280 Good instincts. 2243 01:43:16,280 --> 01:43:19,160 But that's why you probably wouldn't want to write this code yourself 2244 01:43:19,160 --> 01:43:22,076 because then you have to think of all of those corner cases as opposed 2245 01:43:22,076 --> 01:43:25,040 to focusing on the parts you care about. 2246 01:43:25,040 --> 01:43:27,270 All right, so there's one final example. 2247 01:43:27,270 --> 01:43:32,700 And it's perhaps to come full circle here, do we even need the server? 2248 01:43:32,700 --> 01:43:36,420 These 140,000 words right now are in a file called large. 2249 01:43:36,420 --> 01:43:39,720 My web application loads that file into memory and then searches it. 2250 01:43:39,720 --> 01:43:42,840 But who else could search over a big list of files? 2251 01:43:42,840 --> 01:43:45,690 2252 01:43:45,690 --> 01:43:48,670 Where else could we put this logic? 2253 01:43:48,670 --> 01:43:49,630 The browser, right? 2254 01:43:49,630 --> 01:43:52,150 Browser gives you JavaScript, JavaScript's a language, 2255 01:43:52,150 --> 01:43:54,070 languages can search things. 2256 01:43:54,070 --> 01:43:55,960 So let me try this instead. 2257 01:43:55,960 --> 01:44:00,670 In our words 3 example here, notice that I've got one new file. 2258 01:44:00,670 --> 01:44:04,450 In advance, you know, I took my big text file that just had one word per line 2259 01:44:04,450 --> 01:44:06,670 and I put it into a standard format just because it 2260 01:44:06,670 --> 01:44:08,350 makes my life a little easier. 2261 01:44:08,350 --> 01:44:10,450 And I called it large.json. 2262 01:44:10,450 --> 01:44:16,180 And in there, actually, where if I open up this folder, you'll see large.js, 2263 01:44:16,180 --> 01:44:20,080 which is a second file, this time a JavaScript file, 2264 01:44:20,080 --> 01:44:26,080 in which I've just declared a JavaScript array of all 140,000 words 2265 01:44:26,080 --> 01:44:27,170 for better or for worse. 2266 01:44:27,170 --> 01:44:29,170 I just put them into a slightly different format 2267 01:44:29,170 --> 01:44:31,390 with commas, and quotes, and square brackets, 2268 01:44:31,390 --> 01:44:35,630 and I gave this whole thing a variable name at the very top of the file. 2269 01:44:35,630 --> 01:44:36,830 Now, why is this useful? 2270 01:44:36,830 --> 01:44:39,670 Well, if I go into index.html, notice that there 2271 01:44:39,670 --> 01:44:43,240 is no more application.py or templates for this example whatsoever. 2272 01:44:43,240 --> 01:44:45,460 We've gotten rid of Python entirely, I don't 2273 01:44:45,460 --> 01:44:48,130 know if it's for the better or worse, but we'll now see. 2274 01:44:48,130 --> 01:44:51,940 So in this file, notice we have an input tag as before, 2275 01:44:51,940 --> 01:44:55,540 a placeholder for all of the ULs, but we're also 2276 01:44:55,540 --> 01:44:57,910 now including this large.js file. 2277 01:44:57,910 --> 01:45:02,290 Thereby telling the browser please download all 140,000 words 2278 01:45:02,290 --> 01:45:04,540 and then search them locally. 2279 01:45:04,540 --> 01:45:06,190 How am I going to search it locally? 2280 01:45:06,190 --> 01:45:09,130 I've essentially converted the language I wrote in Python a bit 2281 01:45:09,130 --> 01:45:11,990 ago into JavaScript as follows. 2282 01:45:11,990 --> 01:45:16,630 Here says the browser go get me the input that the user can type into. 2283 01:45:16,630 --> 01:45:19,300 This tells the browser, go ahead and listen for key up. 2284 01:45:19,300 --> 01:45:21,301 Whenever that happens, please call this function 2285 01:45:21,301 --> 01:45:24,049 which has no name, because I want you to just call it immediately, 2286 01:45:24,049 --> 01:45:25,240 I don't need its name. 2287 01:45:25,240 --> 01:45:27,860 This function is defined by these several lines. 2288 01:45:27,860 --> 01:45:30,370 These several lines have to do a bit more work than before. 2289 01:45:30,370 --> 01:45:32,590 Because before the server was doing all the hard work 2290 01:45:32,590 --> 01:45:36,410 sending back all of the data, and we just jammed it into the web page. 2291 01:45:36,410 --> 01:45:40,420 But here I'm going to build up a list a little more manually. 2292 01:45:40,420 --> 01:45:42,310 So I'm going to let a variable called html 2293 01:45:42,310 --> 01:45:46,000 equals quote unquote, because I want to build up the unordered list myself. 2294 01:45:46,000 --> 01:45:48,010 Then if the human, indeed, types something in-- 2295 01:45:48,010 --> 01:45:52,000 so if their input is non null, so if they type at least one character, 2296 01:45:52,000 --> 01:45:53,172 do the following. 2297 01:45:53,172 --> 01:45:54,880 This is weird in JavaScript, but when you 2298 01:45:54,880 --> 01:45:59,440 iterate over an array in JavaScript, you use the preposition of not in. 2299 01:45:59,440 --> 01:46:03,610 So for word of words, go ahead and do the following. 2300 01:46:03,610 --> 01:46:07,690 If the current word starts with-- notice the capitalized w-- also 2301 01:46:07,690 --> 01:46:10,600 different from Python, but same idea, just different spelling-- 2302 01:46:10,600 --> 01:46:14,620 if the word I'm iterating over starts with whatever the human inputted, 2303 01:46:14,620 --> 01:46:15,910 we found a match. 2304 01:46:15,910 --> 01:46:18,760 Go ahead and append to this HTML variable, 2305 01:46:18,760 --> 01:46:22,270 open bracket LI closed bracket, concatenate the word to it, 2306 01:46:22,270 --> 01:46:25,060 and then close bracket, as well. 2307 01:46:25,060 --> 01:46:28,450 So I'm constructing a variable in the browser's memory 2308 01:46:28,450 --> 01:46:32,360 containing HTML that I want to jam into the DOM ultimately. 2309 01:46:32,360 --> 01:46:33,260 How do I do that. 2310 01:46:33,260 --> 01:46:37,240 Well, at the very last line I say to the document, select the UL tag, 2311 01:46:37,240 --> 01:46:39,900 go inside of its HTML, and change whatever 2312 01:46:39,900 --> 01:46:46,070 is there to this string of HTML, which is presumably 0 or more LI tags 2313 01:46:46,070 --> 01:46:47,960 now based on those search results. 2314 01:46:47,960 --> 01:46:50,851 So now let me go back to words 1-- 2315 01:46:50,851 --> 01:46:53,510 rather, let me go back to this example here. 2316 01:46:53,510 --> 01:46:55,110 Let me go ahead and serve this up. 2317 01:46:55,110 --> 01:46:58,550 It's not Flask anymore, so I have to use our server from two weeks ago, 2318 01:46:58,550 --> 01:47:01,210 HTTP server, to serve up HTML. 2319 01:47:01,210 --> 01:47:06,130 Let me go ahead and reload the screen here, open up index.html, and now 2320 01:47:06,130 --> 01:47:08,569 notice we're good to go. 2321 01:47:08,569 --> 01:47:09,860 What do you want to search for? 2322 01:47:09,860 --> 01:47:15,730 A, B, C. And let's open up the Network tab. 2323 01:47:15,730 --> 01:47:17,369 Inspect, Network. 2324 01:47:17,369 --> 01:47:19,160 Let's see what happens every time I search. 2325 01:47:19,160 --> 01:47:26,922 Z, Y, Q, A. Why is there no network traffic now? 2326 01:47:26,922 --> 01:47:28,610 AUDIENCE: There's no network traffic. 2327 01:47:28,610 --> 01:47:30,276 DAVID MALAN: OK, but that's what I said. 2328 01:47:30,276 --> 01:47:32,620 But why is there no network traffic? 2329 01:47:32,620 --> 01:47:35,530 It's not sending any routes, it's not talking to a backend server. 2330 01:47:35,530 --> 01:47:36,030 Why? 2331 01:47:36,030 --> 01:47:38,980 Because all the data I might need is already local. 2332 01:47:38,980 --> 01:47:41,170 So mixed messages here, too. 2333 01:47:41,170 --> 01:47:42,887 Which is better, which is right? 2334 01:47:42,887 --> 01:47:43,720 What's the takeaway? 2335 01:47:43,720 --> 01:47:44,770 How do you think about this? 2336 01:47:44,770 --> 01:47:47,410 Because now, whereas a lot of our programs early on in the semester 2337 01:47:47,410 --> 01:47:50,410 were relatively small even though they didn't feel that way at the time, 2338 01:47:50,410 --> 01:47:52,930 now we have even more design possibilities. 2339 01:47:52,930 --> 01:47:55,060 And the answers are increasingly non-obvious, 2340 01:47:55,060 --> 01:47:57,010 and this is why you as programmers will just 2341 01:47:57,010 --> 01:47:59,232 get more comfortable with conventions, you'll maybe 2342 01:47:59,232 --> 01:48:00,940 practice what you've seen preached first, 2343 01:48:00,940 --> 01:48:02,890 then you'll decide as you might be already saying, 2344 01:48:02,890 --> 01:48:05,181 I don't like that, I'm going to do this some other way. 2345 01:48:05,181 --> 01:48:08,530 So how do you think about which of these several words examples is best? 2346 01:48:08,530 --> 01:48:11,080 Version 0 was let the server do all the work 2347 01:48:11,080 --> 01:48:15,250 and just send back a full new page of results like Google in 1999 did. 2348 01:48:15,250 --> 01:48:18,310 Then version 1, we added a bit of JavaScript 2349 01:48:18,310 --> 01:48:21,880 that used jQuery the library to talk to the server using 2350 01:48:21,880 --> 01:48:23,170 a technique called Ajax-- 2351 01:48:23,170 --> 01:48:24,640 asynchronous JavaScript and XML-- 2352 01:48:24,640 --> 01:48:28,090 but that just means go get me more data and we returned LI elements. 2353 01:48:28,090 --> 01:48:29,980 Then we decided that's a little sloppy, don't 2354 01:48:29,980 --> 01:48:31,930 seem to send me all these useless tags, just 2355 01:48:31,930 --> 01:48:34,180 send a comma separated list of words. 2356 01:48:34,180 --> 01:48:35,337 That was version 2. 2357 01:48:35,337 --> 01:48:37,420 And then this last version gets rid of all of that 2358 01:48:37,420 --> 01:48:39,211 and just sends all the words to the browser 2359 01:48:39,211 --> 01:48:43,350 and lets it deal with it entirely. 2360 01:48:43,350 --> 01:48:48,320 Who likes which best, 0, 1, 2, or 3? 2361 01:48:48,320 --> 01:48:49,236 What do you think? 2362 01:48:49,236 --> 01:48:52,670 AUDIENCE: So if you aren't supposed to trust the user in case 2363 01:48:52,670 --> 01:48:55,940 they turn off the JavaScript, then their decision of the functionality 2364 01:48:55,940 --> 01:48:57,590 of the website works. 2365 01:48:57,590 --> 01:48:59,131 DAVID MALAN: That's a good trade-off. 2366 01:48:59,131 --> 01:49:02,374 So if the user turns off JavaScript, 3-- 2367 01:49:02,374 --> 01:49:03,540 OK, it won't offend anyone-- 2368 01:49:03,540 --> 01:49:07,530 3 2, and 1 won't work anymore because JavaScript's disabled. 2369 01:49:07,530 --> 01:49:09,080 Now, do you care about that? 2370 01:49:09,080 --> 01:49:09,740 Maybe not. 2371 01:49:09,740 --> 01:49:11,917 It's a small number of users on the internet who 2372 01:49:11,917 --> 01:49:14,750 are so concerned with this they just turn off JavaScript altogether, 2373 01:49:14,750 --> 01:49:17,958 and the reality is so many websites just break these days without JavaScript. 2374 01:49:17,958 --> 01:49:20,155 That might be a reasonable cost of doing business. 2375 01:49:20,155 --> 01:49:20,780 Other thoughts? 2376 01:49:20,780 --> 01:49:21,426 Yeah? 2377 01:49:21,426 --> 01:49:23,330 AUDIENCE: Is the last version the fastest? 2378 01:49:23,330 --> 01:49:25,204 DAVID MALAN: Is the last version the fastest? 2379 01:49:25,204 --> 01:49:29,370 I don't know, how could we assess that? 2380 01:49:29,370 --> 01:49:31,120 Yeah, I mean, we can literally measure it. 2381 01:49:31,120 --> 01:49:34,492 And honestly, built into Chrome in other tabs that I've not even clicked on 2382 01:49:34,492 --> 01:49:36,700 are a lot of performance tools where you can actually 2383 01:49:36,700 --> 01:49:38,569 monitor how long everything's taking. 2384 01:49:38,569 --> 01:49:40,360 This is called benchmarking more generally, 2385 01:49:40,360 --> 01:49:42,610 and this is what you did essentially in the speller problems 2386 01:49:42,610 --> 01:49:44,650 that even though we wrote the code that timed everything 2387 01:49:44,650 --> 01:49:46,691 and measured everything, to answer that question, 2388 01:49:46,691 --> 01:49:49,809 you could just try timing every one of the examples 2389 01:49:49,809 --> 01:49:51,850 and then decide for yourself which is best, sure. 2390 01:49:51,850 --> 01:49:52,690 Yeah? 2391 01:49:52,690 --> 01:49:54,940 AUDIENCE: The last thing I have with problematic issue 2392 01:49:54,940 --> 01:49:57,995 is like my phone's old, and it doesn't have a lot of memory, 2393 01:49:57,995 --> 01:50:00,550 and I may not have the fastest plan on Earth. 2394 01:50:00,550 --> 01:50:06,059 So you might be charging me more data, you might be slowing my phone down. 2395 01:50:06,059 --> 01:50:07,600 DAVID MALAN: Very reasonable concern. 2396 01:50:07,600 --> 01:50:13,070 Let me go into our dictionary file here and list the size of this. 2397 01:50:13,070 --> 01:50:17,750 That large.js file is 2.2 megabytes, which on mobile devices, 2398 01:50:17,750 --> 01:50:21,326 especially in places where your signal is slow, or your bytes are expensive, 2399 01:50:21,326 --> 01:50:23,200 or you only have intermittent access, I mean, 2400 01:50:23,200 --> 01:50:26,230 that's kind of obnoxious to send two megabytes to the user 2401 01:50:26,230 --> 01:50:30,430 if you can avoid it, especially when you can send only the subset of results, 2402 01:50:30,430 --> 01:50:33,392 a few kilobytes maybe, of matches instead. 2403 01:50:33,392 --> 01:50:34,600 So a very reasonable concern. 2404 01:50:34,600 --> 01:50:36,365 Cost, user experience, performance. 2405 01:50:36,365 --> 01:50:36,990 Other thoughts? 2406 01:50:36,990 --> 01:50:39,650 2407 01:50:39,650 --> 01:50:42,890 Which is better for people on university and corporate campuses who tend 2408 01:50:42,890 --> 01:50:46,380 to have really good internet access? 2409 01:50:46,380 --> 01:50:47,140 Say again? 2410 01:50:47,140 --> 01:50:47,970 3, OK. 2411 01:50:47,970 --> 01:50:50,010 But what if it's not 140,000 words, but it's 2412 01:50:50,010 --> 01:50:54,600 like a billion pictures of cats that Google indexes? 2413 01:50:54,600 --> 01:50:58,031 Or hundreds or thousands of friends and all of their profile data? 2414 01:50:58,031 --> 01:51:00,030 Like at some point there's this inflection point 2415 01:51:00,030 --> 01:51:01,820 where too much data, right? 2416 01:51:01,820 --> 01:51:03,279 It's not reasonable, it's too much. 2417 01:51:03,279 --> 01:51:05,778 You don't want to just get a copy of your corporate database 2418 01:51:05,778 --> 01:51:08,460 to every one of your users just for them to search more locally. 2419 01:51:08,460 --> 01:51:10,080 So again, these are the non-obvious questions. 2420 01:51:10,080 --> 01:51:12,370 And one of the goals of, frankly, the final project 2421 01:51:12,370 --> 01:51:15,480 if you do something web based, or mobile based, or C based, or anything, 2422 01:51:15,480 --> 01:51:17,580 is all of these questions now boil down to you. 2423 01:51:17,580 --> 01:51:20,130 Like we have no well-defined answers in mind 2424 01:51:20,130 --> 01:51:23,310 as to what your final project should do and how it should do it best. 2425 01:51:23,310 --> 01:51:26,160 But in the weeks ahead, you'll be pre-proposing some project ideas, 2426 01:51:26,160 --> 01:51:29,416 proposing an actual project idea, and then designing and implementing this. 2427 01:51:29,416 --> 01:51:31,290 And you, too, will probably feel this tension 2428 01:51:31,290 --> 01:51:34,410 where the answer is not always obvious, your teaching fellow might not even 2429 01:51:34,410 --> 01:51:36,090 know how to answer your question, because he or she will 2430 01:51:36,090 --> 01:51:37,214 have thoughts of their own. 2431 01:51:37,214 --> 01:51:38,520 But it's ultimately up to you. 2432 01:51:38,520 --> 01:51:42,330 And we're now at the point of a level of coding maturity 2433 01:51:42,330 --> 01:51:45,240 where we're taking the training wheels off and more of the decisions 2434 01:51:45,240 --> 01:51:47,100 are now left to you. 2435 01:51:47,100 --> 01:51:48,120 Let's end here. 2436 01:51:48,120 --> 01:51:50,119 Stick around for one on one questions, and we'll 2437 01:51:50,119 --> 01:51:52,220 see you next week for databases.