All language subtitles for 2022_lecture9-720p-en

af Afrikaans
sq Albanian
am Amharic
ar Arabic
hy Armenian
az Azerbaijani
eu Basque
be Belarusian
bn Bengali
bs Bosnian
bg Bulgarian
ca Catalan
ceb Cebuano
ny Chichewa
zh-CN Chinese (Simplified)
zh-TW Chinese (Traditional)
co Corsican
hr Croatian
cs Czech
da Danish
nl Dutch
en English
eo Esperanto
et Estonian
tl Filipino
fi Finnish
fr French
fy Frisian
gl Galician
ka Georgian
de German
el Greek
gu Gujarati
ht Haitian Creole
ha Hausa
haw Hawaiian
iw Hebrew
hi Hindi
hmn Hmong
hu Hungarian
is Icelandic
ig Igbo
id Indonesian
ga Irish
it Italian
ja Japanese
jw Javanese
kn Kannada
kk Kazakh
km Khmer
ko Korean
ku Kurdish (Kurmanji)
ky Kyrgyz
lo Lao
la Latin
lv Latvian
lt Lithuanian
lb Luxembourgish
mk Macedonian
mg Malagasy
ms Malay
ml Malayalam
mt Maltese
mi Maori
mr Marathi
mn Mongolian
my Myanmar (Burmese)
ne Nepali
no Norwegian
ps Pashto
fa Persian
pl Polish
pt Portuguese
pa Punjabi
ro Romanian
ru Russian
sm Samoan
gd Scots Gaelic
sr Serbian
st Sesotho
sn Shona
sd Sindhi
si Sinhala
sk Slovak
sl Slovenian
so Somali
es Spanish
su Sundanese
sw Swahili
sv Swedish
tg Tajik
ta Tamil
te Telugu
th Thai
tr Turkish
uk Ukrainian Download
ur Urdu
uz Uzbek
vi Vietnamese
cy Welsh
xh Xhosa
yi Yiddish
yo Yoruba
zu Zulu
or Odia (Oriya)
rw Kinyarwanda
tk Turkmen
tt Tatar
ug Uyghur
Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated: 0 00:00:00,000 --> 00:00:03,472 [MUSIC PLAYING] 1 00:00:03,472 --> 00:01:18,510 2 00:01:18,510 --> 00:01:19,410 DAVID: All right. 3 00:01:19,410 --> 00:01:23,460 So this is CS50 and this is week nine, and this is it 4 00:01:23,460 --> 00:01:25,710 in terms of programming fundamentals. 5 00:01:25,710 --> 00:01:28,488 Today, we come rather full circle with so many of the languages 6 00:01:28,488 --> 00:01:30,780 that we've been looking at over the past several weeks. 7 00:01:30,780 --> 00:01:33,750 And with HTML and CSS and JavaScript last week, 8 00:01:33,750 --> 00:01:37,020 we're going to add back into the mix, Python and SQL. 9 00:01:37,020 --> 00:01:40,420 And with that, do we have the ability to program for the web. 10 00:01:40,420 --> 00:01:42,840 And even though this isn't the only user interface out 11 00:01:42,840 --> 00:01:45,930 there, increasingly-- or people certainly using laptops and desktops 12 00:01:45,930 --> 00:01:48,960 and a browser to access applications that people have written, 13 00:01:48,960 --> 00:01:53,550 but it's also, increasingly, the way that mobile apps are written as well. 14 00:01:53,550 --> 00:01:55,770 There are languages called Swift for iOS, 15 00:01:55,770 --> 00:01:57,930 there are languages called Java for Android, 16 00:01:57,930 --> 00:02:00,750 but coding applications in both of those language 17 00:02:00,750 --> 00:02:04,530 means knowing twice as many language, building twice as many applications, 18 00:02:04,530 --> 00:02:05,190 potentially. 19 00:02:05,190 --> 00:02:07,740 So we're increasingly seeing, for better or for worse, 20 00:02:07,740 --> 00:02:09,840 that the world is starting to really standardize, 21 00:02:09,840 --> 00:02:13,740 at least for the next some number of years, on HTML, CSS, and JavaScript 22 00:02:13,740 --> 00:02:17,730 coupled with other languages like Python and SQL on the so-called backend. 23 00:02:17,730 --> 00:02:20,168 And so today, we'll tie all of those together 24 00:02:20,168 --> 00:02:22,710 and give you the last of the tools in your toolkit with which 25 00:02:22,710 --> 00:02:25,290 to tackle final projects to go off into the real world, 26 00:02:25,290 --> 00:02:28,200 ultimately, and somehow solve problems with programming. 27 00:02:28,200 --> 00:02:33,310 But we need an additional tool today, and we've sort of outgrown HTTP server. 28 00:02:33,310 --> 00:02:36,477 This is just a program that comes on certain computers 29 00:02:36,477 --> 00:02:38,310 that you can install for free, happens to be 30 00:02:38,310 --> 00:02:40,980 written in a language called JavaScript, but it's a program 31 00:02:40,980 --> 00:02:44,340 that we've been using to run a web server in VSCO. 32 00:02:44,340 --> 00:02:47,170 But you can run it on your own Mac or PC or anywhere else. 33 00:02:47,170 --> 00:02:50,940 But all this particular HTTP server does is 34 00:02:50,940 --> 00:02:54,750 serve up static content like HTML files, CSS files, 35 00:02:54,750 --> 00:02:59,220 JavaScript files, maybe images, maybe video files, but just static content. 36 00:02:59,220 --> 00:03:03,600 It has no ability to really interact with the user beyond simple clicks. 37 00:03:03,600 --> 00:03:08,800 You can create a web form and serve it visually using HTTP server, 38 00:03:08,800 --> 00:03:12,630 but if the human types in input into a form and click Submit, unless you 39 00:03:12,630 --> 00:03:16,080 submit it elsewhere to something like google.com like we did last time, 40 00:03:16,080 --> 00:03:19,200 it's not actually going to go anywhere because this server can't actually 41 00:03:19,200 --> 00:03:21,460 process the requests that are coming in. 42 00:03:21,460 --> 00:03:24,390 So today, we're going to introduce another type of server that 43 00:03:24,390 --> 00:03:28,350 comes with Python that allows us to not only serve web pages 44 00:03:28,350 --> 00:03:29,970 but also process user input. 45 00:03:29,970 --> 00:03:33,720 And recall that all that input is going to come ultimately from the URL, 46 00:03:33,720 --> 00:03:36,300 or more deeply inside of those virtual envelopes. 47 00:03:36,300 --> 00:03:40,140 So here's the canonical URL we talked about last week for random website 48 00:03:40,140 --> 00:03:42,280 like www.example.com. 49 00:03:42,280 --> 00:03:46,020 And I've highlighted the slash to connote the root of the web server, 50 00:03:46,020 --> 00:03:48,540 like the default folder where, presumably, there's 51 00:03:48,540 --> 00:03:52,150 a file called index.html or something else in there. 52 00:03:52,150 --> 00:03:54,360 Otherwise, you might have a more explicit mention 53 00:03:54,360 --> 00:03:56,790 of the actual file named file.html. 54 00:03:56,790 --> 00:03:59,873 You can have folders, as you probably gleaned from the most recent problem 55 00:03:59,873 --> 00:04:00,373 set. 56 00:04:00,373 --> 00:04:02,460 You can have files in folders like this, and these 57 00:04:02,460 --> 00:04:06,330 are all examples of what a programmer would typically call a path. 58 00:04:06,330 --> 00:04:08,160 So it might not just be a single word, it 59 00:04:08,160 --> 00:04:12,070 might have multiple slashes and multiple folders and some folders and files. 60 00:04:12,070 --> 00:04:14,070 But this is just more generally known as a path. 61 00:04:14,070 --> 00:04:16,709 But there's another term of our, that's essentially equivalent, 62 00:04:16,709 --> 00:04:17,890 that we'll introduce today. 63 00:04:17,890 --> 00:04:21,300 This is also synonymously called a route, which is maybe 64 00:04:21,300 --> 00:04:25,260 a better generic description of what these things are because it turns out 65 00:04:25,260 --> 00:04:27,750 they don't have to map to, that is, refer 66 00:04:27,750 --> 00:04:30,810 to a specific folder or a specific file, you 67 00:04:30,810 --> 00:04:33,333 can come up with your own routes in a website. 68 00:04:33,333 --> 00:04:36,000 And just make sure that when the user visits that, you give them 69 00:04:36,000 --> 00:04:36,900 a certain website page. 70 00:04:36,900 --> 00:04:39,608 If they visit something else, you give them a different web page. 71 00:04:39,608 --> 00:04:42,480 It doesn't have to map to a very specific file, as we'll soon see. 72 00:04:42,480 --> 00:04:45,660 And if you want to get input from the user, just like Google does, 73 00:04:45,660 --> 00:04:50,460 like q=cats, you can add a question mark at the end of this route. 74 00:04:50,460 --> 00:04:54,300 The key, or the HTTP parameter name that you want to define for yourself, 75 00:04:54,300 --> 00:04:57,263 and then equal sum value that, presumably, the human typed in. 76 00:04:57,263 --> 00:04:59,430 If you have more of these, you can put an ampersand, 77 00:04:59,430 --> 00:05:04,140 and then more key equals value pairs ampersand, repeat, repeat, repeat. 78 00:05:04,140 --> 00:05:08,770 The catch, though, is that using the tools that we had last week alone, 79 00:05:08,770 --> 00:05:13,920 we don't really have the ability to parse, that is, to analyze and extract 80 00:05:13,920 --> 00:05:15,840 things like q equals cats. 81 00:05:15,840 --> 00:05:18,900 You could have appended question mark q equals cats or anything else 82 00:05:18,900 --> 00:05:22,800 to any of URLs in your home page for problem set eight, 83 00:05:22,800 --> 00:05:26,460 but it doesn't actually do anything useful, necessarily, 84 00:05:26,460 --> 00:05:28,350 unless you use some fancy JavaScript. 85 00:05:28,350 --> 00:05:31,480 The server is not going to bother even looking in that for you. 86 00:05:31,480 --> 00:05:34,380 But today, we're going to introduce using a bit of Python. 87 00:05:34,380 --> 00:05:38,220 And in fact, we're going to use a web server implemented in Python, instead 88 00:05:38,220 --> 00:05:41,550 of using HTTP server alone, to automatically, for you, 89 00:05:41,550 --> 00:05:44,430 look for any key value pairs after the question mark 90 00:05:44,430 --> 00:05:48,120 and then hand them to you in the form of a Python dictionary. 91 00:05:48,120 --> 00:05:52,020 Recall that a dictionary in Python, a dict object, is just key value pairs. 92 00:05:52,020 --> 00:05:56,155 That seems like a perfect fit for these kinds of parameters. 93 00:05:56,155 --> 00:05:58,530 And you're not going to have to write that code yourself. 94 00:05:58,530 --> 00:06:02,140 It's going to be handed to you by way of what's called a framework. 95 00:06:02,140 --> 00:06:04,020 So this will be the second of two frameworks, 96 00:06:04,020 --> 00:06:05,562 really, that we look at in the class. 97 00:06:05,562 --> 00:06:08,250 And a framework is essentially a bunch of libraries 98 00:06:08,250 --> 00:06:10,740 that someone else wrote and a set of conventions, 99 00:06:10,740 --> 00:06:12,190 therefore, for doing things. 100 00:06:12,190 --> 00:06:15,000 So those of you who really started dabbling with Bootstrap 101 00:06:15,000 --> 00:06:18,680 this past week to make your home pages prettier and nicely laid out, 102 00:06:18,680 --> 00:06:19,950 you are using a framework. 103 00:06:19,950 --> 00:06:20,450 Why? 104 00:06:20,450 --> 00:06:24,110 Well, you're using libraries, code that someone else wrote, like all the CSS, 105 00:06:24,110 --> 00:06:27,200 maybe some of the JavaScript that the Bootstrap people wrote for you. 106 00:06:27,200 --> 00:06:30,980 But it's also a framework in the sense that you have to go all in. 107 00:06:30,980 --> 00:06:33,500 You have to use Bootstraps classes, and you 108 00:06:33,500 --> 00:06:37,820 have to lay out your divs or your spans or your table tags 109 00:06:37,820 --> 00:06:39,663 in a sort of Bootstrap-friendly way. 110 00:06:39,663 --> 00:06:42,080 And it's not too onerous, but you're following conventions 111 00:06:42,080 --> 00:06:43,920 that a bunch of humans standardized on. 112 00:06:43,920 --> 00:06:47,660 So similarly, in the world of Python, is there another framework 113 00:06:47,660 --> 00:06:49,040 we're going to start using today. 114 00:06:49,040 --> 00:06:52,430 And whereas Bootstrap is used for CSS and JavaScript, 115 00:06:52,430 --> 00:06:54,470 Flask is going to be used for Python. 116 00:06:54,470 --> 00:06:57,170 And it just solves a lot of common problems for us. 117 00:06:57,170 --> 00:07:00,380 It's going to make it easier for us to analyze the URLs 118 00:07:00,380 --> 00:07:03,020 and get key value pairs, it's going to make it easier 119 00:07:03,020 --> 00:07:06,110 for us to find files or images that the human wants 120 00:07:06,110 --> 00:07:07,550 to see when visiting our website. 121 00:07:07,550 --> 00:07:10,442 It's even going to make it easier to send emails automatically, 122 00:07:10,442 --> 00:07:11,900 like when someone fills out a form. 123 00:07:11,900 --> 00:07:15,210 You can dynamically, using code, send them an email as well. 124 00:07:15,210 --> 00:07:17,510 So Flask, and with it some related libraries, 125 00:07:17,510 --> 00:07:20,750 it's just going to make stuff like that easier for us. 126 00:07:20,750 --> 00:07:25,340 And to do this, all we have to do is adhere to some pretty minimalist 127 00:07:25,340 --> 00:07:27,450 requirements of this framework. 128 00:07:27,450 --> 00:07:30,650 We're going to have to create a file for ourselves called app.py, 129 00:07:30,650 --> 00:07:33,650 this is where our web app or application is going to live. 130 00:07:33,650 --> 00:07:38,120 If we have any libraries that we want to use, the convention in the Python world 131 00:07:38,120 --> 00:07:41,750 is to have a very simple text file called requirements.txt 132 00:07:41,750 --> 00:07:44,090 where you list the names of those libraries, 133 00:07:44,090 --> 00:07:48,890 top to bottom, in that text file, similar in spirit to the include 134 00:07:48,890 --> 00:07:52,650 or the import statements that we saw in C and Python, respectively. 135 00:07:52,650 --> 00:07:55,700 We're going to have a static folder or static directory, which 136 00:07:55,700 --> 00:07:58,850 means any files you create that are not ever going to change, 137 00:07:58,850 --> 00:08:01,442 like images, CSS files, JavaScript files, 138 00:08:01,442 --> 00:08:02,900 they're going to go in this folder. 139 00:08:02,900 --> 00:08:05,750 And then lastly, any HTML that you write, 140 00:08:05,750 --> 00:08:08,150 web pages you want the human to see, are going 141 00:08:08,150 --> 00:08:09,990 to go in a folder called templates. 142 00:08:09,990 --> 00:08:12,950 So this is, again, evidence of what we mean by a framework. 143 00:08:12,950 --> 00:08:14,750 Do you have to make a web app like this? 144 00:08:14,750 --> 00:08:16,940 No, but if you're using this particular framework, 145 00:08:16,940 --> 00:08:20,990 this is what people decided would be the human conventions. 146 00:08:20,990 --> 00:08:25,200 If you've heard of other frameworks like Django or asp.net or bunches of others, 147 00:08:25,200 --> 00:08:28,370 there are just different conventions out there for creating applications. 148 00:08:28,370 --> 00:08:32,390 Flask is a very nice microframework in that that's it. 149 00:08:32,390 --> 00:08:35,870 All you have to do is adhere to these pretty minimalist requirements 150 00:08:35,870 --> 00:08:38,840 to get some code up and running. 151 00:08:38,840 --> 00:08:41,620 All right, so let's go ahead and make a web app. 152 00:08:41,620 --> 00:08:43,370 Let me go ahead and switch over to VS Code 153 00:08:43,370 --> 00:08:45,412 here, and let me practice what I'm preaching here 154 00:08:45,412 --> 00:08:47,720 by first creating app.py. 155 00:08:47,720 --> 00:08:51,410 And let's go ahead and create an application that very simply, 156 00:08:51,410 --> 00:08:53,700 maybe, says hello to the user. 157 00:08:53,700 --> 00:08:58,160 So something that, initially, is not all that dynamic, pretty static, in fact. 158 00:08:58,160 --> 00:09:00,120 But we'll build on that as we've always done. 159 00:09:00,120 --> 00:09:04,100 So in app.py, what I'm going to do first is exactly the line of code 160 00:09:04,100 --> 00:09:05,420 I had on the screen earlier. 161 00:09:05,420 --> 00:09:11,840 From Flask, import Flask, with a capital F second and a lowercase f first. 162 00:09:11,840 --> 00:09:14,390 And I'm also going to preemptively import 163 00:09:14,390 --> 00:09:18,440 a couple of functions, render template, and request. 164 00:09:18,440 --> 00:09:20,360 More on those in just a bit. 165 00:09:20,360 --> 00:09:23,000 And then below that, I'm going to say, go ahead and do this. 166 00:09:23,000 --> 00:09:25,730 Give me a web-- a variable called app that's 167 00:09:25,730 --> 00:09:29,930 going to be the result of calling the Flask function and passing in it 168 00:09:29,930 --> 00:09:32,400 this weird incantation here, name. 169 00:09:32,400 --> 00:09:35,810 So we've seen this a few weeks back when we played around with Python 170 00:09:35,810 --> 00:09:38,540 and we had that if main thing at the bottom of the screen. 171 00:09:38,540 --> 00:09:44,090 For now, just know that __name__ refers to the name of the current file. 172 00:09:44,090 --> 00:09:48,560 And so this line here, simple as it is, tells Python, hey, Python, 173 00:09:48,560 --> 00:09:52,310 turn this file into a Flask application. 174 00:09:52,310 --> 00:09:56,030 Flask is a function that just figures out, then, how to do the rest. 175 00:09:56,030 --> 00:09:59,630 The last thing I'm going to do for this very simple web application is this. 176 00:09:59,630 --> 00:10:03,290 I'm going to say that I'm going to have a function called 177 00:10:03,290 --> 00:10:05,210 index that takes no arguments. 178 00:10:05,210 --> 00:10:07,130 And whenever this function is called, I want 179 00:10:07,130 --> 00:10:12,560 to return the results of rendering a template called index.html. 180 00:10:12,560 --> 00:10:13,515 And that's it. 181 00:10:13,515 --> 00:10:15,890 So let's assume there's a file somewhere, haven't created 182 00:10:15,890 --> 00:10:17,720 it yet, called index.html. 183 00:10:17,720 --> 00:10:19,940 But render template means render this file 184 00:10:19,940 --> 00:10:23,400 that is printed to the user's screen, so to speak. 185 00:10:23,400 --> 00:10:26,210 The last thing I'm going to do is I have to tell Flask 186 00:10:26,210 --> 00:10:28,500 when to call this index function. 187 00:10:28,500 --> 00:10:34,166 And so I'm going to tell it to define a route for, quote unquote, "slash." 188 00:10:34,166 --> 00:10:35,268 And that's it. 189 00:10:35,268 --> 00:10:37,310 So let's take a look at what I just created here. 190 00:10:37,310 --> 00:10:40,280 This is slightly new syntax, and it's really the only weirdness 191 00:10:40,280 --> 00:10:42,050 that we'll have today in Python. 192 00:10:42,050 --> 00:10:44,750 This is what's known in Python is what's called a decorator. 193 00:10:44,750 --> 00:10:46,760 A decorator is a special type of function 194 00:10:46,760 --> 00:10:49,310 that modifies, essentially, another function. 195 00:10:49,310 --> 00:10:52,350 For our purposes, just know that on line six this says, 196 00:10:52,350 --> 00:10:55,700 hey Python, define a route for slash, the default 197 00:10:55,700 --> 00:10:57,500 page on my website application. 198 00:10:57,500 --> 00:10:59,900 The next two lines, seven and eight, say, hey Python, 199 00:10:59,900 --> 00:11:02,630 define a function called index, takes no arguments. 200 00:11:02,630 --> 00:11:07,520 And the only thing you should ever do is return render template of quote unquote 201 00:11:07,520 --> 00:11:09,540 "index.html." 202 00:11:09,540 --> 00:11:10,650 All right, so that's it. 203 00:11:10,650 --> 00:11:13,700 So really, the next question, naturally, should be all right, well, 204 00:11:13,700 --> 00:11:17,490 what is in index.html? 205 00:11:17,490 --> 00:11:19,230 Well, let me go ahead and do that next. 206 00:11:19,230 --> 00:11:22,500 Let me create a directory called templates, practicing, again, 207 00:11:22,500 --> 00:11:23,760 what I preached earlier. 208 00:11:23,760 --> 00:11:26,520 So I'm going to create a new empty directory called templates, 209 00:11:26,520 --> 00:11:30,240 I'm going to go and CD into that directory 210 00:11:30,240 --> 00:11:33,900 and then do code of index.html. 211 00:11:33,900 --> 00:11:35,520 So here is going to be my index page. 212 00:11:35,520 --> 00:11:38,465 And I'm going to do a very simple web page, doc type HTML. 213 00:11:38,465 --> 00:11:40,590 I'm just going to borrow some stuff from last week. 214 00:11:40,590 --> 00:11:42,840 HTML language equals English. 215 00:11:42,840 --> 00:11:44,010 I'll close that tag. 216 00:11:44,010 --> 00:11:47,730 I'll then do a head tag, I'll do a meta tag, the name of which is viewport. 217 00:11:47,730 --> 00:11:50,250 This makes my site recall responsive. 218 00:11:50,250 --> 00:11:52,980 That is, it just grows and shrink to fit the size of the device. 219 00:11:52,980 --> 00:11:56,460 The initial scale for which is going to be one, and the width of which 220 00:11:56,460 --> 00:11:58,500 is going to be device width. 221 00:11:58,500 --> 00:12:00,540 So I'm typing this out, I have it printed here. 222 00:12:00,540 --> 00:12:02,490 This is stuff I typically copy paste. 223 00:12:02,490 --> 00:12:05,190 But then lastly, I'm going to add in my title, which will just 224 00:12:05,190 --> 00:12:06,750 be hello for the name of this app. 225 00:12:06,750 --> 00:12:07,750 And then the body-- 226 00:12:07,750 --> 00:12:08,640 whoops, Bobby. 227 00:12:08,640 --> 00:12:12,510 The body of this tag will be-- 228 00:12:12,510 --> 00:12:13,470 there we go. 229 00:12:13,470 --> 00:12:17,140 The body of this page, rather, will just be hello comma world. 230 00:12:17,140 --> 00:12:20,680 So very uninteresting and really a regression to where we began last week. 231 00:12:20,680 --> 00:12:24,030 But let's go now and experiment with these two files. 232 00:12:24,030 --> 00:12:25,890 I'm not going to bother with a static folder 233 00:12:25,890 --> 00:12:28,890 right now, because I don't have any other files that I want to serve up. 234 00:12:28,890 --> 00:12:30,990 No images, no CSS, nothing like that. 235 00:12:30,990 --> 00:12:34,000 And honestly, requirements.txt is going to be pretty simple. 236 00:12:34,000 --> 00:12:37,800 I'm going to go requirements.txt and just say make sure the system has 237 00:12:37,800 --> 00:12:41,190 access to the Flask library itself. 238 00:12:41,190 --> 00:12:44,190 All right, but that's the only thing we can add in there for now. 239 00:12:44,190 --> 00:12:49,470 All right, so now I have two files, app.py, and I have index.html. 240 00:12:49,470 --> 00:12:52,950 But index.html thank you is inside of my templates directory 241 00:12:52,950 --> 00:12:55,450 so how do I actually start a web server last week, 242 00:12:55,450 --> 00:12:56,730 I would have said HTTP server. 243 00:12:56,730 --> 00:12:59,070 But HTTP server is not a Python thing. 244 00:12:59,070 --> 00:13:03,390 It has no idea about Flask or Python or anything I just wrote. 245 00:13:03,390 --> 00:13:06,220 HTTP server will just spit out static files. 246 00:13:06,220 --> 00:13:09,525 So if I ran HTTP server, and then I clicked on app.py, 247 00:13:09,525 --> 00:13:11,490 I would literally see my Python code. 248 00:13:11,490 --> 00:13:15,660 It would not get executed because HTTP server is just for static content. 249 00:13:15,660 --> 00:13:19,740 But today, I'm going to run a different command called Flask run. 250 00:13:19,740 --> 00:13:23,490 So this framework Flask that I actually preinstalled in advance, 251 00:13:23,490 --> 00:13:27,180 so it wasn't strictly necessary that I create that requirements.txt file just 252 00:13:27,180 --> 00:13:31,140 yet, comes with a program called Flask, takes command line arguments like 253 00:13:31,140 --> 00:13:34,710 the word run, and when I do that, you'll see somewhat similar output to last 254 00:13:34,710 --> 00:13:36,900 week whereby you'll see the name-- 255 00:13:36,900 --> 00:13:39,867 your URL for your unique preview of that. 256 00:13:39,867 --> 00:13:42,450 You might see a pop up saying that your application is running 257 00:13:42,450 --> 00:13:44,400 on TCP port, something or other. 258 00:13:44,400 --> 00:13:46,830 By default, last week, we used port 8080. 259 00:13:46,830 --> 00:13:49,860 Flask, just because, prefers port 5,000. 260 00:13:49,860 --> 00:13:50,940 So that's fine too. 261 00:13:50,940 --> 00:13:53,670 I'm going to go ahead and open up this URL now. 262 00:13:53,670 --> 00:13:55,890 And once it authenticates and redirects me, 263 00:13:55,890 --> 00:13:59,460 just to make sure I'm allowed to access that particular port, let me zoom in. 264 00:13:59,460 --> 00:14:02,460 Voila, there's the extent of this application. 265 00:14:02,460 --> 00:14:06,150 If I view source by right-clicking or control clicking, 266 00:14:06,150 --> 00:14:08,130 there's my HTML that's been spit out. 267 00:14:08,130 --> 00:14:11,070 So really, I've just reinvented the wheel from last week 268 00:14:11,070 --> 00:14:13,510 because there's no dynamism now, nothing at all. 269 00:14:13,510 --> 00:14:15,207 But what if I do this? 270 00:14:15,207 --> 00:14:17,040 Let me close the source and let me zoom out. 271 00:14:17,040 --> 00:14:18,660 So you can see my URL bar. 272 00:14:18,660 --> 00:14:21,840 Let me zoom in now, and I have a very unique cryptic URL. 273 00:14:21,840 --> 00:14:23,820 But the point is that it ends with nothing. 274 00:14:23,820 --> 00:14:26,040 Or implicitly, it ends with slash. 275 00:14:26,040 --> 00:14:27,930 This is just Chrome being a little helpful. 276 00:14:27,930 --> 00:14:31,000 It doesn't bother showing you a slash, even though it's implicitly there. 277 00:14:31,000 --> 00:14:37,110 But let me do something explicit like my name equals, quote unquote, "David." 278 00:14:37,110 --> 00:14:39,480 So there's a key value pair that I've manually 279 00:14:39,480 --> 00:14:42,900 typed into my URL bar and hit Enter. 280 00:14:42,900 --> 00:14:44,400 Nothing happens, nothing changes. 281 00:14:44,400 --> 00:14:45,900 It still says hello, world. 282 00:14:45,900 --> 00:14:50,220 But the opportunity today is to now, dynamically, get at the input 283 00:14:50,220 --> 00:14:53,410 from that URL and start displaying it to the user. 284 00:14:53,410 --> 00:14:57,610 So let me go back over here to my terminal window and code. 285 00:14:57,610 --> 00:15:00,060 Let me move that down to the bottom there. 286 00:15:00,060 --> 00:15:03,280 And what if I want to say, huh, hello, name. 287 00:15:03,280 --> 00:15:05,010 I ideally want to say something like-- 288 00:15:05,010 --> 00:15:06,630 I don't want to hard code David because then it's never 289 00:15:06,630 --> 00:15:08,520 going to say hello to anyone else. 290 00:15:08,520 --> 00:15:14,010 I want to put like a variable name here, like name should go here. 291 00:15:14,010 --> 00:15:17,550 But it's not an HTML tag, so I need some kind of placeholder. 292 00:15:17,550 --> 00:15:19,680 Well, here's what I can do. 293 00:15:19,680 --> 00:15:24,810 If I go back to my Python code, I can now define a variable called name. 294 00:15:24,810 --> 00:15:28,800 And I can ask Flask to go into the current request, 295 00:15:28,800 --> 00:15:32,670 into its arguments, that is in the URL, as they're called, 296 00:15:32,670 --> 00:15:36,960 and get whatever the value of the parameter called name is. 297 00:15:36,960 --> 00:15:39,030 That puts that into a variable for me. 298 00:15:39,030 --> 00:15:41,940 And then, in render template-- this is one of those functions 299 00:15:41,940 --> 00:15:43,800 that can take more than one argument. 300 00:15:43,800 --> 00:15:45,780 If it takes another argument, you can pass 301 00:15:45,780 --> 00:15:47,740 in the name of any variable you want. 302 00:15:47,740 --> 00:15:52,210 So if I want to pass in my name, I can literally say name equals name. 303 00:15:52,210 --> 00:15:56,970 So this is the name of a variable I want to give to the template. 304 00:15:56,970 --> 00:16:01,920 This is the actual variable that I want to get the value from. 305 00:16:01,920 --> 00:16:07,920 And now lastly, in my index.html, the syntax as of today in Flask, 306 00:16:07,920 --> 00:16:12,030 is to do two curly braces and then put the name of the variable 307 00:16:12,030 --> 00:16:13,592 that you want to plug in. 308 00:16:13,592 --> 00:16:15,860 So here's what we mean by a template. 309 00:16:15,860 --> 00:16:18,950 A template is like a blueprint in the real world, where 310 00:16:18,950 --> 00:16:21,080 it's plans to make something. 311 00:16:21,080 --> 00:16:24,950 This is the plan to make a web page that has all of this code literally, 312 00:16:24,950 --> 00:16:28,460 but there's this placeholder with two curly braces here and here 313 00:16:28,460 --> 00:16:32,880 that says go ahead and plug in the value of the name variable right there. 314 00:16:32,880 --> 00:16:35,450 So in this sense, it's similar in spirit to our f strings 315 00:16:35,450 --> 00:16:36,980 or format strings in Python. 316 00:16:36,980 --> 00:16:39,897 The syntax is a little different just because reasonable people 317 00:16:39,897 --> 00:16:42,230 disagree, different people, different frameworks come up 318 00:16:42,230 --> 00:16:43,355 with different conventions. 319 00:16:43,355 --> 00:16:46,220 The convention in Flask, in their templates, 320 00:16:46,220 --> 00:16:48,680 is to use two curly braces here. 321 00:16:48,680 --> 00:16:50,960 The hope is that you, the programmer, will never 322 00:16:50,960 --> 00:16:54,480 want to display two curly braces in your actual web page. 323 00:16:54,480 --> 00:16:56,670 But even if you do, there's a workaround. 324 00:16:56,670 --> 00:16:57,810 We can escape that. 325 00:16:57,810 --> 00:17:01,250 So now let me go ahead and go back to my browser tab here. 326 00:17:01,250 --> 00:17:04,160 Previously, even though I added name equals David 327 00:17:04,160 --> 00:17:07,190 to the end of the URL with a question mark, it still said hello, world. 328 00:17:07,190 --> 00:17:09,920 But now, hopefully, if I made these changes, 329 00:17:09,920 --> 00:17:13,589 let me go ahead and open up my terminal window. 330 00:17:13,589 --> 00:17:17,670 Let me restart Flask so it loads my changes by default. 331 00:17:17,670 --> 00:17:21,619 Let me go back to my hello tab and click reload so it grabs the page anew 332 00:17:21,619 --> 00:17:23,240 from the server. 333 00:17:23,240 --> 00:17:24,710 And there we go, hello, David. 334 00:17:24,710 --> 00:17:27,740 I can play around now and I can change the URL appear to, for instance, 335 00:17:27,740 --> 00:17:28,280 Carter. 336 00:17:28,280 --> 00:17:30,080 Zoom out, hit Enter. 337 00:17:30,080 --> 00:17:32,790 And now we have something more dynamic. 338 00:17:32,790 --> 00:17:36,980 So the new pieces here are, in Python, we have some code here 339 00:17:36,980 --> 00:17:40,790 that allows us to access, programmatically, everything 340 00:17:40,790 --> 00:17:42,950 that's after the question mark in the URL. 341 00:17:42,950 --> 00:17:48,860 And the only thing we have to do that is call this function request.args.get. 342 00:17:48,860 --> 00:17:50,690 You and I don't have to bother figuring out 343 00:17:50,690 --> 00:17:53,107 where is the question mark, where is the equal sign, where 344 00:17:53,107 --> 00:17:54,680 are the ampersands, potentially. 345 00:17:54,680 --> 00:17:58,460 The framework, Flask, does all of that for us. 346 00:17:58,460 --> 00:18:05,490 OK, any questions then on these principles thus far? 347 00:18:05,490 --> 00:18:06,795 Yeah, in back. 348 00:18:06,795 --> 00:18:12,380 AUDIENCE: Why do you say the question mark in the URL? 349 00:18:12,380 --> 00:18:14,810 DAVID: Why do you need a question mark in the URL? 350 00:18:14,810 --> 00:18:21,390 The short answer is just because that is where key value pairs must go. 351 00:18:21,390 --> 00:18:24,990 If you're making a GET request from a browser to a server, 352 00:18:24,990 --> 00:18:29,690 the convention, standardized by the HTTP protocol, is to put them in the URL 353 00:18:29,690 --> 00:18:33,390 after the so-called route or path, then a question mark. 354 00:18:33,390 --> 00:18:35,840 And it delineates what's part of the root or the path, 355 00:18:35,840 --> 00:18:39,990 and what's part of the human input to the right. 356 00:18:39,990 --> 00:18:40,800 Other questions? 357 00:18:40,800 --> 00:18:41,465 Yeah. 358 00:18:41,465 --> 00:18:45,110 AUDIENCE: Can you go over again why the left and right in the [INAUDIBLE]?? 359 00:18:45,110 --> 00:18:45,610 DAVID: Sure. 360 00:18:45,610 --> 00:18:47,740 This is this annoying thing about Python. 361 00:18:47,740 --> 00:18:51,790 When you pass in parameters, two functions that have names, 362 00:18:51,790 --> 00:18:54,710 you typically say something equals something else. 363 00:18:54,710 --> 00:18:57,280 So let me make a slight tweak here. 364 00:18:57,280 --> 00:19:01,610 How about I say name of person here. 365 00:19:01,610 --> 00:19:06,460 This allows me to invent my own variable for my template 366 00:19:06,460 --> 00:19:08,450 and assign it the value of name. 367 00:19:08,450 --> 00:19:14,915 I now, though, have to go into my index file and say name of person-- 368 00:19:14,915 --> 00:19:15,790 did I get that right? 369 00:19:15,790 --> 00:19:17,290 Name of person, yeah. 370 00:19:17,290 --> 00:19:19,310 So these two have to match. 371 00:19:19,310 --> 00:19:22,690 And so this is just stupid because it's unnecessarily verbose. 372 00:19:22,690 --> 00:19:26,680 So what typically people do is they just use the same name as the variable 373 00:19:26,680 --> 00:19:30,600 itself, even though it looks admittedly stupid, but it has two different roles. 374 00:19:30,600 --> 00:19:32,350 The thing to the left of the equal sign is 375 00:19:32,350 --> 00:19:36,460 the name of the variable you plan to use in the template, the thing on the right 376 00:19:36,460 --> 00:19:38,470 is the actual value you're assigning it. 377 00:19:38,470 --> 00:19:40,330 And this is because its general purpose. 378 00:19:40,330 --> 00:19:43,570 I could override this and I could say something like name always 379 00:19:43,570 --> 00:19:46,120 equals Emma, no matter what that variable is. 380 00:19:46,120 --> 00:19:48,430 And now if I go back to my browser and reload, 381 00:19:48,430 --> 00:19:52,360 no matter what's in the URL, David or Carter, It's always-- 382 00:19:52,360 --> 00:19:55,210 OK, Emma broke the server. 383 00:19:55,210 --> 00:19:56,380 What did I do? 384 00:19:56,380 --> 00:19:58,840 Oh, I didn't change my template back. 385 00:19:58,840 --> 00:19:59,380 There we go. 386 00:19:59,380 --> 00:20:02,650 Let me change that back to be name, so that it's name there 387 00:20:02,650 --> 00:20:03,580 and it's name here. 388 00:20:03,580 --> 00:20:06,130 But I've hardcoded Emma's name, so now we're 389 00:20:06,130 --> 00:20:09,730 only ever going to see Emma no matter whose name is in the URL. 390 00:20:09,730 --> 00:20:10,760 That's all. 391 00:20:10,760 --> 00:20:14,020 All right, so this is bad user interface. 392 00:20:14,020 --> 00:20:16,930 If, in order to get a greeting for the day, you, the user, 393 00:20:16,930 --> 00:20:19,420 have to manually change the URL, which none of us ever do. 394 00:20:19,420 --> 00:20:21,220 This is not how web pages work. 395 00:20:21,220 --> 00:20:25,210 What is the more normal mechanism for getting input from the user 396 00:20:25,210 --> 00:20:28,900 and putting it in that URL automatically? 397 00:20:28,900 --> 00:20:31,780 How did we do that last week? 398 00:20:31,780 --> 00:20:33,500 With Google, if you recall. 399 00:20:33,500 --> 00:20:38,190 AUDIENCE: We have the search bar and we [INAUDIBLE] you have 400 00:20:38,190 --> 00:20:44,340 to make something in there [INAUDIBLE]. 401 00:20:44,340 --> 00:20:47,970 DAVID: OK, so we did make something in order to get the input from the user. 402 00:20:47,970 --> 00:20:51,840 And specifically, what was the tag or the terminology we used last week? 403 00:20:51,840 --> 00:20:53,070 AUDIENCE: [INAUDIBLE]. 404 00:20:53,070 --> 00:20:55,000 DAVID: Sorry, a little louder? 405 00:20:55,000 --> 00:20:57,010 Oh, no. 406 00:20:57,010 --> 00:20:57,510 But yeah. 407 00:20:57,510 --> 00:20:58,680 AUDIENCE: Is it input? 408 00:20:58,680 --> 00:21:01,030 DAVID: So the input tag, inside of the form tag. 409 00:21:01,030 --> 00:21:03,775 So in short, forms, or of course, how the web works 410 00:21:03,775 --> 00:21:05,650 and how we typically get input from the user, 411 00:21:05,650 --> 00:21:08,978 whether it's a button or a text box or a dropdown menu or something else. 412 00:21:08,978 --> 00:21:11,020 So let's go ahead and add that into the mix here. 413 00:21:11,020 --> 00:21:14,940 So let's enhance this hello app to do a little something more by, 414 00:21:14,940 --> 00:21:16,240 this time, just doing this. 415 00:21:16,240 --> 00:21:20,340 Let me get rid of this name stuff and let me just 416 00:21:20,340 --> 00:21:26,130 have a very simple index.html file that, by default, is going to simply ask 417 00:21:26,130 --> 00:21:28,480 the user for some input as follows. 418 00:21:28,480 --> 00:21:33,090 I'm going to go back into my index.html, and instead of printing out 419 00:21:33,090 --> 00:21:36,090 the user's name, this is the page I'm going to use to actually get input 420 00:21:36,090 --> 00:21:36,880 from the user. 421 00:21:36,880 --> 00:21:39,210 So I'm going to create a form tag. 422 00:21:39,210 --> 00:21:42,870 The method I'm going to use for now is going to be, quote unquote, "get." 423 00:21:42,870 --> 00:21:45,330 Then, inside of that form, I'm going to have an input tag. 424 00:21:45,330 --> 00:21:47,872 And I'm going to turn off autocomplete like we did last week. 425 00:21:47,872 --> 00:21:51,780 I'm going to turn on auto focus, so it puts the cursor in the text box for me. 426 00:21:51,780 --> 00:21:55,502 I'm going to give the name of this input the name, name. 427 00:21:55,502 --> 00:21:58,210 Not to be too confusing, but I'm asking the human for their name. 428 00:21:58,210 --> 00:22:01,770 So it makes sense that the name of the input should be, quote unquote, "name." 429 00:22:01,770 --> 00:22:04,470 The placeholder I want the human to see in light gray text 430 00:22:04,470 --> 00:22:07,500 will be Name with a capital N, just so it's a little grammatical. 431 00:22:07,500 --> 00:22:09,750 And then type of this text fiel-- 432 00:22:09,750 --> 00:22:11,610 type of this input is going to be text. 433 00:22:11,610 --> 00:22:14,550 Then I'm just going to give myself, like last week, a submit button. 434 00:22:14,550 --> 00:22:16,467 And I don't care what it says, it's just going 435 00:22:16,467 --> 00:22:18,820 to say the default submit terminology. 436 00:22:18,820 --> 00:22:23,310 Let me go ahead, now, and open up my terminal window again. 437 00:22:23,310 --> 00:22:28,470 Let me go to that same URL so that I can see-- whoops. 438 00:22:28,470 --> 00:22:33,320 439 00:22:33,320 --> 00:22:33,990 There we go. 440 00:22:33,990 --> 00:22:35,540 So that was just cached from earlier. 441 00:22:35,540 --> 00:22:38,840 Let me go back to that same URL, my GitHub preview.dev URL, 442 00:22:38,840 --> 00:22:40,260 and here I have the form. 443 00:22:40,260 --> 00:22:42,170 And now, I can type in anything I want. 444 00:22:42,170 --> 00:22:45,840 The catch, though, is when I click Submit, where is it going to go? 445 00:22:45,840 --> 00:22:46,880 Well, let's be explicit. 446 00:22:46,880 --> 00:22:50,240 It does have a default value, but let me go into my index.html 447 00:22:50,240 --> 00:22:53,000 and let me add, just like we did last week for it, Google. 448 00:22:53,000 --> 00:22:58,427 Whereas previously, I said something like www.google.com/search, but today, 449 00:22:58,427 --> 00:23:00,260 we're not going to rely on some third party. 450 00:23:00,260 --> 00:23:02,720 I'm going to implement the so-called backend, 451 00:23:02,720 --> 00:23:06,990 and I'm going to have the user submit this form to a second route, 452 00:23:06,990 --> 00:23:09,620 not just slash, how about /greet. 453 00:23:09,620 --> 00:23:11,180 I can make it up, whatever I want. 454 00:23:11,180 --> 00:23:15,650 Greet feels like a nice operative word, so /greet is where the user will be 455 00:23:15,650 --> 00:23:18,650 sent when they click Submit on this form. 456 00:23:18,650 --> 00:23:22,130 All right, so let's go ahead now and go back to my browser tab. 457 00:23:22,130 --> 00:23:24,830 Let me go ahead, actually, and let me reload Flask 458 00:23:24,830 --> 00:23:27,320 here so that it reloads all of my changes. 459 00:23:27,320 --> 00:23:31,400 Let me reload this tab so that I get the very latest HTML and, indeed, 460 00:23:31,400 --> 00:23:32,510 quick safety check. 461 00:23:32,510 --> 00:23:35,630 If I view page source, we indeed see that my browser 462 00:23:35,630 --> 00:23:37,490 has downloaded the latest HTML. 463 00:23:37,490 --> 00:23:39,155 So it definitely has changed. 464 00:23:39,155 --> 00:23:40,530 Let's go ahead and type in David. 465 00:23:40,530 --> 00:23:44,300 And when I click Submit here, what's going to happen? 466 00:23:44,300 --> 00:23:44,980 Hypotheses. 467 00:23:44,980 --> 00:23:47,500 468 00:23:47,500 --> 00:23:50,620 What's going to happen visually, functionally, however you 469 00:23:50,620 --> 00:23:54,540 want to interpret when I click Submit. 470 00:23:54,540 --> 00:23:55,040 Yeah? 471 00:23:55,040 --> 00:23:56,585 AUDIENCE: [INAUDIBLE] an empty page. 472 00:23:56,585 --> 00:23:58,710 DAVID: OK, the user's going to go to an empty page. 473 00:23:58,710 --> 00:24:00,002 Pretty good instinct, because-- 474 00:24:00,002 --> 00:24:02,880 no where else, if I mentioned /greet, it doesn't seem to exist. 475 00:24:02,880 --> 00:24:07,110 How's the URL going to change, just to be clear? 476 00:24:07,110 --> 00:24:09,360 What's going to appear, suddenly, in the URL? 477 00:24:09,360 --> 00:24:12,050 478 00:24:12,050 --> 00:24:12,925 Yeah? 479 00:24:12,925 --> 00:24:14,200 AUDIENCE: 404? 480 00:24:14,200 --> 00:24:15,010 DAVID: 404? 481 00:24:15,010 --> 00:24:15,802 No, not in the URL. 482 00:24:15,802 --> 00:24:18,677 Specifically in the URL, something's going to get added automatically 483 00:24:18,677 --> 00:24:19,232 when I click. 484 00:24:19,232 --> 00:24:20,440 AUDIENCE: The key value pair? 485 00:24:20,440 --> 00:24:21,815 DAVID: The key value pair, right. 486 00:24:21,815 --> 00:24:22,900 That's how forms work. 487 00:24:22,900 --> 00:24:25,180 That's why our Google trick last week worked. 488 00:24:25,180 --> 00:24:27,843 I sort of recreated a form on my own website. 489 00:24:27,843 --> 00:24:30,760 And even though I didn't get around to implementing google.com itself, 490 00:24:30,760 --> 00:24:34,420 I can still send the information to Google just relying on browsers, 491 00:24:34,420 --> 00:24:35,590 standardizing-- 492 00:24:35,590 --> 00:24:38,470 to your question earlier, that whenever you submit a form, 493 00:24:38,470 --> 00:24:41,740 it automatically ends up after a question mark in the URL 494 00:24:41,740 --> 00:24:42,670 if you're using GET. 495 00:24:42,670 --> 00:24:45,460 So this both of you are right, this is going to break. 496 00:24:45,460 --> 00:24:49,000 And all three of you are right, in effect, 404 not found. 497 00:24:49,000 --> 00:24:50,450 You can see it in the tab here. 498 00:24:50,450 --> 00:24:51,950 That's the error that has come back. 499 00:24:51,950 --> 00:24:55,720 But what's interesting, and most important, the URL did change. 500 00:24:55,720 --> 00:24:59,890 And it went to /greet?name=david. 501 00:24:59,890 --> 00:25:02,260 So I just, now, need to add some logic that actually 502 00:25:02,260 --> 00:25:04,000 looks for that so-called route. 503 00:25:04,000 --> 00:25:06,520 So let me go back to my app.py. 504 00:25:06,520 --> 00:25:11,680 Let me define another route for, quote unquote, "slash greet." 505 00:25:11,680 --> 00:25:15,200 And then, inside of-- under this, let me define another function. 506 00:25:15,200 --> 00:25:18,280 I'll call it greet, but I could call it anything I want. 507 00:25:18,280 --> 00:25:20,950 No arguments, for now, for this, and then 508 00:25:20,950 --> 00:25:24,430 let me go ahead and do this in my app.py. 509 00:25:24,430 --> 00:25:27,290 This time around, I do want to get the human's name. 510 00:25:27,290 --> 00:25:31,300 So let me say requeste.args get quote unquote "name", 511 00:25:31,300 --> 00:25:33,340 and let me store that in a variable called name. 512 00:25:33,340 --> 00:25:37,030 Then let me return a template, and you know 513 00:25:37,030 --> 00:25:39,610 what, I'm going to give myself a new template, greet.html. 514 00:25:39,610 --> 00:25:41,860 Because this has a different purpose, it's not a form. 515 00:25:41,860 --> 00:25:44,800 I want to say hello to the user in this HTML file, 516 00:25:44,800 --> 00:25:49,960 and I want to pass, into it, the name that the human just typed in. 517 00:25:49,960 --> 00:25:56,320 All right, so now if I go up and reload the page, what might happen now? 518 00:25:56,320 --> 00:25:58,480 Other logical check here. 519 00:25:58,480 --> 00:26:01,930 If I go ahead and hit reload or resubmit the form, what might happen now? 520 00:26:01,930 --> 00:26:05,200 521 00:26:05,200 --> 00:26:08,480 Any instincts? 522 00:26:08,480 --> 00:26:10,890 Let me try, so let's try this. 523 00:26:10,890 --> 00:26:12,470 Let's go ahead and reload the page. 524 00:26:12,470 --> 00:26:13,980 Previously, it was not found. 525 00:26:13,980 --> 00:26:17,900 Now it's worse, and this is the 500 error, internal server 526 00:26:17,900 --> 00:26:22,130 error that I promised next week we will all encounter accidentally, ultimately. 527 00:26:22,130 --> 00:26:24,020 But here we have an internal server error. 528 00:26:24,020 --> 00:26:27,750 Because it's an internal error, this means something's wrong with your code. 529 00:26:27,750 --> 00:26:31,280 So the route was actually found because it's not a 404 this time. 530 00:26:31,280 --> 00:26:36,740 But if we go into VS Code here and we look at the console, the terminal 531 00:26:36,740 --> 00:26:39,860 window, you'll see that-- 532 00:26:39,860 --> 00:26:43,280 this is actually a bit misleading. 533 00:26:43,280 --> 00:26:44,370 Do I want to do this? 534 00:26:44,370 --> 00:26:46,350 Let me reload this. 535 00:26:46,350 --> 00:26:47,370 Let me reload here. 536 00:26:47,370 --> 00:26:49,730 Oh, standby. 537 00:26:49,730 --> 00:26:51,120 Come on. 538 00:26:51,120 --> 00:26:53,100 There we go. 539 00:26:53,100 --> 00:26:54,440 Come on. 540 00:26:54,440 --> 00:26:57,110 OK, here we have this error here, and this 541 00:26:57,110 --> 00:26:59,480 is where your terminal window is going to be helpful. 542 00:26:59,480 --> 00:27:02,390 In your terminal window, by default, is typically 543 00:27:02,390 --> 00:27:05,510 going to go helpful stuff like a log, L-O-G, 544 00:27:05,510 --> 00:27:08,847 of what it is the server is seeing from the browser. 545 00:27:08,847 --> 00:27:11,180 For instance, here's what the server just saw in purple. 546 00:27:11,180 --> 00:27:16,310 Get /greet?name=david using HTTP version 1.0. 547 00:27:16,310 --> 00:27:19,790 Here, though, is the status code that the server returned, 500. 548 00:27:19,790 --> 00:27:20,840 Why, what's the error? 549 00:27:20,840 --> 00:27:24,260 Well, here's where we get these annoying pretty cryptic Python messages 550 00:27:24,260 --> 00:27:26,090 that help50 might ultimately help you with, 551 00:27:26,090 --> 00:27:29,403 or here, we might just have a clue at the bottom. 552 00:27:29,403 --> 00:27:31,820 And this is actually pretty clear, even though we've never 553 00:27:31,820 --> 00:27:32,810 seen this error before. 554 00:27:32,810 --> 00:27:34,130 What did I screw up here? 555 00:27:34,130 --> 00:27:36,710 I just didn't create greet.html, right? 556 00:27:36,710 --> 00:27:37,737 Template not found. 557 00:27:37,737 --> 00:27:40,070 All right, so that must be the last piece of the puzzle. 558 00:27:40,070 --> 00:27:43,460 And again, representative of how you might diagnose problems like these, 559 00:27:43,460 --> 00:27:46,550 let me go into my terminal window. 560 00:27:46,550 --> 00:27:51,050 After hitting Control C, which cancels or interrupts a process, 561 00:27:51,050 --> 00:27:53,030 let me go into my templates directory. 562 00:27:53,030 --> 00:27:55,910 If I type ls, I only have index.html. 563 00:27:55,910 --> 00:27:58,460 So let's code up greet.html. 564 00:27:58,460 --> 00:28:02,360 And in this file let's quickly do doc type. 565 00:28:02,360 --> 00:28:07,160 Doc type HTML, open bracket HTML, language equals English. 566 00:28:07,160 --> 00:28:11,090 Inside of this, I'll have the head tag, inside of here, I'll have the meta. 567 00:28:11,090 --> 00:28:15,740 The name is viewport, the content of which is-- 568 00:28:15,740 --> 00:28:18,020 I always forget this to. 569 00:28:18,020 --> 00:28:25,220 The content of which is initial scale equals one, width equals device width. 570 00:28:25,220 --> 00:28:28,130 Quote unquote, title is still going to be, 571 00:28:28,130 --> 00:28:30,530 I'll call this greet because this is my template. 572 00:28:30,530 --> 00:28:35,880 And then here, in the body, I'm going to have hello comma name. 573 00:28:35,880 --> 00:28:40,100 So I could have kept around the old version of this, but I just recreated, 574 00:28:40,100 --> 00:28:41,570 essentially, my second template. 575 00:28:41,570 --> 00:28:45,200 So index.html now is almost the same, but the title is different 576 00:28:45,200 --> 00:28:46,580 and it has a form. 577 00:28:46,580 --> 00:28:49,790 greet.html is almost the same, but it does not have a form. 578 00:28:49,790 --> 00:28:52,020 It just has the hello comma name. 579 00:28:52,020 --> 00:28:56,510 So let me now go ahead and rerun in the correct directory. 580 00:28:56,510 --> 00:29:01,080 You have to run Flask wherever app.py is, not in your templates directory. 581 00:29:01,080 --> 00:29:04,040 So let me do Flask run to get back to where I was. 582 00:29:04,040 --> 00:29:05,900 Let me go into my other tab. 583 00:29:05,900 --> 00:29:09,080 Cross my fingers this time that, when I go back to slash 584 00:29:09,080 --> 00:29:14,030 and I get index.html's form, now I type in David and click Submit, 585 00:29:14,030 --> 00:29:16,730 now we get hello, David. 586 00:29:16,730 --> 00:29:20,240 And now we have a full-fledged web app that has two different routes, 587 00:29:20,240 --> 00:29:25,430 slash and /greet, the latter of which takes input like this and then, 588 00:29:25,430 --> 00:29:27,470 using a template, spits it out. 589 00:29:27,470 --> 00:29:30,990 But something could go wrong, and let's see what happens here. 590 00:29:30,990 --> 00:29:33,620 Suppose I don't type anything in. 591 00:29:33,620 --> 00:29:35,870 Let me go here and just click Submit. 592 00:29:35,870 --> 00:29:38,662 Now, I mean, it looks stupid. 593 00:29:38,662 --> 00:29:40,620 So there's bunches of ways we could solve this. 594 00:29:40,620 --> 00:29:44,060 I could require that the user have input on the previous page, 595 00:29:44,060 --> 00:29:46,193 I could have some kind of error check for this. 596 00:29:46,193 --> 00:29:48,860 But there's another mechanism I can use that I'll just show you. 597 00:29:48,860 --> 00:29:53,150 It turns out this GET function, in the context of HTTP 598 00:29:53,150 --> 00:29:55,400 and also in general with Python dictionaries, 599 00:29:55,400 --> 00:29:57,810 you can actually supply a default value. 600 00:29:57,810 --> 00:30:02,180 So if there is no name parameter or no value for a name parameter, 601 00:30:02,180 --> 00:30:04,830 you can actually give it a default value like this. 602 00:30:04,830 --> 00:30:07,010 So I'll say world, for instance. 603 00:30:07,010 --> 00:30:08,450 Now, let me go back here. 604 00:30:08,450 --> 00:30:10,580 Let me type in nothing again and click Submit. 605 00:30:10,580 --> 00:30:14,270 And hopefully this time, I'll do-- oops, sorry. 606 00:30:14,270 --> 00:30:17,030 Let me restart Flask to reload the template. 607 00:30:17,030 --> 00:30:20,090 Let me go ahead and type nothing this time, clicking Submit. 608 00:30:20,090 --> 00:30:23,300 And hopefully, we now-- 609 00:30:23,300 --> 00:30:26,210 Oh, interesting. 610 00:30:26,210 --> 00:30:27,860 I should have faked this. 611 00:30:27,860 --> 00:30:31,700 Suppose that the reason this-- 612 00:30:31,700 --> 00:30:33,260 Oh. 613 00:30:33,260 --> 00:30:37,430 Suppose I just get rid of name altogether like this and hit Enter. 614 00:30:37,430 --> 00:30:40,070 Now I see hello, world, and this is a subtlety 615 00:30:40,070 --> 00:30:42,200 that I didn't intend to get into here. 616 00:30:42,200 --> 00:30:45,620 When you have question mark name equals nothing, 617 00:30:45,620 --> 00:30:47,660 you're passing in what's called-- whoops. 618 00:30:47,660 --> 00:30:51,350 When you have greet question mark name equals something, 619 00:30:51,350 --> 00:30:54,080 you actually are giving a value to name. 620 00:30:54,080 --> 00:30:56,720 It is quote unquote with nothing in between. 621 00:30:56,720 --> 00:30:59,190 That is different from having no value at all. 622 00:30:59,190 --> 00:31:03,203 So allow me to just propose that the error here, we 623 00:31:03,203 --> 00:31:05,120 would want to require this in a different way. 624 00:31:05,120 --> 00:31:07,610 And probably the most robust way to do this 625 00:31:07,610 --> 00:31:13,260 would be to go in here, in my HTML, and say that the name field is required. 626 00:31:13,260 --> 00:31:17,990 Now, if I go back to my form after restarting Flask here, 627 00:31:17,990 --> 00:31:21,950 and I go ahead and click reload on my form and type in nothing 628 00:31:21,950 --> 00:31:25,580 and click Submit, now the browser is going to yell at me. 629 00:31:25,580 --> 00:31:27,740 But just as a teaser for something we'll be 630 00:31:27,740 --> 00:31:30,470 doing in the next problem set in terms of error checking, 631 00:31:30,470 --> 00:31:37,010 you should never, ever, ever rely on client side safety checks like this. 632 00:31:37,010 --> 00:31:41,540 Because we know, from last week, that a curious programmer can go to inspect, 633 00:31:41,540 --> 00:31:43,920 and let me poke around the HTML here. 634 00:31:43,920 --> 00:31:46,280 Let me go into the body, the form. 635 00:31:46,280 --> 00:31:48,900 OK, you say required, I say not required. 636 00:31:48,900 --> 00:31:51,960 You can just delete what's in the dom, in the browser, 637 00:31:51,960 --> 00:31:54,920 and now I can go ahead and submit this form. 638 00:31:54,920 --> 00:31:56,510 And it appears to be broken. 639 00:31:56,510 --> 00:31:59,700 Not a big deal with a silly little greeting application like this. 640 00:31:59,700 --> 00:32:02,750 But if you're trying to require that humans actually 641 00:32:02,750 --> 00:32:06,140 provide input that is necessary for the correct operation of the site, 642 00:32:06,140 --> 00:32:11,690 you don't want to trust that the HTML is not altered by some adversary. 643 00:32:11,690 --> 00:32:14,570 All right, any questions, then, on this particular app 644 00:32:14,570 --> 00:32:18,450 before we add another feature here? 645 00:32:18,450 --> 00:32:21,203 Any questions here? 646 00:32:21,203 --> 00:32:22,185 Yeah. 647 00:32:22,185 --> 00:32:24,149 AUDIENCE: Do you guys [INAUDIBLE]. 648 00:32:24,149 --> 00:32:26,493 649 00:32:26,493 --> 00:32:27,660 DAVID: Sorry, little louder. 650 00:32:27,660 --> 00:32:29,163 In the index function-- 651 00:32:29,163 --> 00:32:30,612 AUDIENCE: Oh, sorry. 652 00:32:30,612 --> 00:32:33,030 [INAUDIBLE] 653 00:32:33,030 --> 00:32:33,807 DAVID: Sorry? 654 00:32:33,807 --> 00:32:36,508 AUDIENCE: [INAUDIBLE] 655 00:32:36,508 --> 00:32:38,050 DAVID: Would it be a problem if what? 656 00:32:38,050 --> 00:32:39,523 AUDIENCE: You have to [INAUDIBLE]. 657 00:32:39,523 --> 00:32:42,390 658 00:32:42,390 --> 00:32:42,890 DAVID: No. 659 00:32:42,890 --> 00:32:44,360 I mean no, this is OK. 660 00:32:44,360 --> 00:32:46,760 What you should really do is something we're going to do with another example 661 00:32:46,760 --> 00:32:48,330 where I'm going to start error checking things. 662 00:32:48,330 --> 00:32:50,030 So let me wave my hands at that and propose that we'll 663 00:32:50,030 --> 00:32:51,498 solve this better in just a bit. 664 00:32:51,498 --> 00:32:53,540 But it's not bad to do what I just did here, it's 665 00:32:53,540 --> 00:32:56,480 only going to handle one of the scenarios that I was worried about. 666 00:32:56,480 --> 00:32:57,990 Not all of them. 667 00:32:57,990 --> 00:33:00,290 All right, so even though this is new to most of us 668 00:33:00,290 --> 00:33:05,630 here, consider index.html, my first template, and consider greet.html, 669 00:33:05,630 --> 00:33:07,790 my second template. 670 00:33:07,790 --> 00:33:11,022 What might be arguably badly designed? 671 00:33:11,022 --> 00:33:12,980 Even though this might be the first time you've 672 00:33:12,980 --> 00:33:16,700 ever touched web programming like this. 673 00:33:16,700 --> 00:33:24,140 What's bad or dumb about this design of these two templates alone? 674 00:33:24,140 --> 00:33:28,070 And there's a reason, too, that I bored us by typing it out that second time. 675 00:33:28,070 --> 00:33:28,880 Yeah? 676 00:33:28,880 --> 00:33:33,653 AUDIENCE: [INAUDIBLE] you said, stuff like Notepad and [INAUDIBLE].. 677 00:33:33,653 --> 00:33:35,320 DAVID: Yeah, there's so much repetition. 678 00:33:35,320 --> 00:33:38,560 I mean, it was deliberately tedious that I was retyping everything. 679 00:33:38,560 --> 00:33:41,590 The doc type, the HTML tag, the head tag, the title tag. 680 00:33:41,590 --> 00:33:44,230 And little things did change along the way, like the title 681 00:33:44,230 --> 00:33:46,270 and certainly, the content of the body. 682 00:33:46,270 --> 00:33:49,540 But so much of this, I mean, almost all of the page 683 00:33:49,540 --> 00:33:52,837 is a copy of itself in multiple files. 684 00:33:52,837 --> 00:33:56,170 And God forbid we have a third template, a fourth template, a hundredth template 685 00:33:56,170 --> 00:33:57,310 for a really big website. 686 00:33:57,310 --> 00:33:59,680 This is going to get very tedious very quickly. 687 00:33:59,680 --> 00:34:02,208 And suppose you want to change something in one place, 688 00:34:02,208 --> 00:34:05,500 you're going to have to change it now in two, three, a hundred different places 689 00:34:05,500 --> 00:34:06,200 instead. 690 00:34:06,200 --> 00:34:08,980 So just like in programming more generally, 691 00:34:08,980 --> 00:34:11,469 we have this ability to factor out commonalities. 692 00:34:11,469 --> 00:34:13,719 So do you in the context of web programming, 693 00:34:13,719 --> 00:34:16,510 and specifically templating, have the ability 694 00:34:16,510 --> 00:34:18,617 to factor out all of those commonalities. 695 00:34:18,617 --> 00:34:20,409 The syntax is going to be a little curious, 696 00:34:20,409 --> 00:34:23,330 but it functionally is pretty straightforward. 697 00:34:23,330 --> 00:34:24,530 Let me go ahead and do this. 698 00:34:24,530 --> 00:34:28,540 Let me go ahead and copy the contents of index.html. 699 00:34:28,540 --> 00:34:31,420 Let me go into my templates directory and code a file that, 700 00:34:31,420 --> 00:34:34,370 by default, is called layout.html. 701 00:34:34,370 --> 00:34:37,989 And let me go ahead, and per your answer, copy all of those 702 00:34:37,989 --> 00:34:40,520 commonalities into this file now instead. 703 00:34:40,520 --> 00:34:43,389 So here I have a file called layout.html. 704 00:34:43,389 --> 00:34:48,550 I don't want to give every page the same title, maybe, but for now that's OK. 705 00:34:48,550 --> 00:34:50,020 I'm going to call everything hello. 706 00:34:50,020 --> 00:34:52,900 But in the body of the page, what I'm going to do here is just 707 00:34:52,900 --> 00:34:57,500 have a placeholder for actual contents that do change. 708 00:34:57,500 --> 00:35:00,370 So in this layout, I'm going to go ahead in here 709 00:35:00,370 --> 00:35:05,060 and just put in the body of my page, how about this syntax? 710 00:35:05,060 --> 00:35:06,610 And this is admittedly new. 711 00:35:06,610 --> 00:35:11,020 Block body, and then percent sign close curly brace. 712 00:35:11,020 --> 00:35:13,210 And then I'm going to do end block. 713 00:35:13,210 --> 00:35:18,130 So a curious syntax here, but this is more template syntax. 714 00:35:18,130 --> 00:35:21,460 The other template syntax we saw before was the two curly braces. 715 00:35:21,460 --> 00:35:23,290 That's for just plugging in values. 716 00:35:23,290 --> 00:35:27,550 There's this other syntax with Flask that allows you to, say, a single curly 717 00:35:27,550 --> 00:35:32,350 brace, a percent sign, and then some functionality like this defining 718 00:35:32,350 --> 00:35:33,130 a block. 719 00:35:33,130 --> 00:35:35,620 And this one's a little weird because there's literally 720 00:35:35,620 --> 00:35:38,960 nothing between the close curly and the open curly brace here. 721 00:35:38,960 --> 00:35:41,440 But let's see what this can do for us. 722 00:35:41,440 --> 00:35:47,920 Let me now go into my index.html, which is where I borrowed most of that code 723 00:35:47,920 --> 00:35:51,190 from, and let me focus on what is minimally different. 724 00:35:51,190 --> 00:35:56,120 The only thing that's really different in this page, title aside, is the form. 725 00:35:56,120 --> 00:35:59,920 So let me go ahead and just cut that form out to my clipboard. 726 00:35:59,920 --> 00:36:02,680 Let me change the first line of index.html 727 00:36:02,680 --> 00:36:08,980 to say this file is going to extend layout.html, 728 00:36:08,980 --> 00:36:11,170 and notice I'm using the curly braces again. 729 00:36:11,170 --> 00:36:14,620 And this file is going to have its own body block 730 00:36:14,620 --> 00:36:19,540 inside of which is just the HTML that I actually 731 00:36:19,540 --> 00:36:22,030 want to make specific to this page. 732 00:36:22,030 --> 00:36:24,290 And I'll keep my indentation nice and neat here. 733 00:36:24,290 --> 00:36:25,780 And let's consider what I've done. 734 00:36:25,780 --> 00:36:28,210 This is starting to look weird fast, and this is now 735 00:36:28,210 --> 00:36:32,110 a mix of HTML with templating code. 736 00:36:32,110 --> 00:36:38,200 Index.html, first line now says, hey, Flask, this file extends layout.html, 737 00:36:38,200 --> 00:36:39,310 whatever that is. 738 00:36:39,310 --> 00:36:42,640 This next line, three through 10, says, hey, Flask, here 739 00:36:42,640 --> 00:36:45,970 is what I consider my body block to be. 740 00:36:45,970 --> 00:36:49,600 Plug this into the layout placeholder. 741 00:36:49,600 --> 00:36:55,850 Therefore, so if I now go back to layout.html, and layout.html, 742 00:36:55,850 --> 00:36:57,910 it's almost all HTML by contrast. 743 00:36:57,910 --> 00:37:00,995 But there is this placeholder, and if I want to put a default value, 744 00:37:00,995 --> 00:37:01,870 I could say-- whoops. 745 00:37:01,870 --> 00:37:03,640 If I want to put a default value, I could 746 00:37:03,640 --> 00:37:07,240 put a default value there just in case some page does not have a body block. 747 00:37:07,240 --> 00:37:09,410 But in general, that's not going to be relevant. 748 00:37:09,410 --> 00:37:13,120 So this is just a placeholder, albeit a little verbose, that says 749 00:37:13,120 --> 00:37:16,730 plug in the page-specific content right here. 750 00:37:16,730 --> 00:37:20,500 So if I go now into greet.html, this one's even easier. 751 00:37:20,500 --> 00:37:23,500 I'm going to cut this content and get rid of everything else. 752 00:37:23,500 --> 00:37:29,080 Greet.html 2 is going to extend layouts, dot HTML extends plural, 753 00:37:29,080 --> 00:37:35,750 and then I'm going to have my body block here simply be this one line of code. 754 00:37:35,750 --> 00:37:38,200 And then I'm going to go ahead and end that block here. 755 00:37:38,200 --> 00:37:41,050 These are not HTML tags, this is not HTML syntax. 756 00:37:41,050 --> 00:37:44,980 Technically, the syntax we keep seeing with the curly braces, 757 00:37:44,980 --> 00:37:51,220 and these now curly braces with percent signs, is an example of Jinja syntax, 758 00:37:51,220 --> 00:37:56,050 J-I-N-J-A, which is a language, that some humans invented, 759 00:37:56,050 --> 00:37:57,970 for this purpose of templating. 760 00:37:57,970 --> 00:38:00,190 And the people who invented Flask decided, 761 00:38:00,190 --> 00:38:02,290 we're not going to come up with our own syntax, 762 00:38:02,290 --> 00:38:06,305 we're going to use these other people's syntax called Jinja syntax. 763 00:38:06,305 --> 00:38:08,680 So again, there starts to be at this point in the course, 764 00:38:08,680 --> 00:38:12,610 and really in computing, a lot of sharing, now, of ideas and sharing 765 00:38:12,610 --> 00:38:13,190 of code. 766 00:38:13,190 --> 00:38:17,080 So Flask is using this syntax, but other libraries and other languages 767 00:38:17,080 --> 00:38:19,270 might also too. 768 00:38:19,270 --> 00:38:24,070 All right, so now index.html is half HTML, 769 00:38:24,070 --> 00:38:26,500 half templating code, Jinja syntax. 770 00:38:26,500 --> 00:38:30,250 Greet.html is almost all Jinja syntax, no tags even, 771 00:38:30,250 --> 00:38:33,820 but because they both extend layout.html, 772 00:38:33,820 --> 00:38:37,150 now I think I've improved the design of this thing. 773 00:38:37,150 --> 00:38:41,180 If I go back to app.py, none of this really needs to change. 774 00:38:41,180 --> 00:38:44,350 I don't change my templates to mention layout.html, 775 00:38:44,350 --> 00:38:47,860 that's already implicit in the fact that we have the extends keyword. 776 00:38:47,860 --> 00:38:50,980 So now if I go ahead and open my terminal window, 777 00:38:50,980 --> 00:38:55,060 go back to the same folder as app.py and do Flask run, 778 00:38:55,060 --> 00:38:57,970 all right, my application is running on port 5000. 779 00:38:57,970 --> 00:39:01,630 Let me now go back to the /route in my browser and hit Enter, 780 00:39:01,630 --> 00:39:02,920 I have this form again. 781 00:39:02,920 --> 00:39:06,490 And just as a little check, let me view the source of the page 782 00:39:06,490 --> 00:39:08,170 that my browser is seeing. 783 00:39:08,170 --> 00:39:10,600 And there's all of the code. 784 00:39:10,600 --> 00:39:13,660 No mention of Jinja, no curly braces, no percent signs. 785 00:39:13,660 --> 00:39:14,335 It's just HTML. 786 00:39:14,335 --> 00:39:16,960 It's not quite pretty printed in the same way, but that's fine. 787 00:39:16,960 --> 00:39:19,502 Because now, we're starting to dynamically generate websites. 788 00:39:19,502 --> 00:39:22,750 And by that, I mean this isn't quite indented nicely or perfectly. 789 00:39:22,750 --> 00:39:23,350 That's fine. 790 00:39:23,350 --> 00:39:26,110 If it's indented in the source code version, 791 00:39:26,110 --> 00:39:28,150 doesn't matter what the browser really sees. 792 00:39:28,150 --> 00:39:30,640 Let me now go ahead and type in my name, click Submit. 793 00:39:30,640 --> 00:39:32,290 I should see, yep, hello, David. 794 00:39:32,290 --> 00:39:34,390 Let me go ahead and view the source of this page. 795 00:39:34,390 --> 00:39:38,450 And we'll see almost the same thing with what's plugged in there. 796 00:39:38,450 --> 00:39:41,980 So this is, now, web programming in the literal sense. 797 00:39:41,980 --> 00:39:45,280 I did not hard code a page that says hello comma David, hello comma Carter, 798 00:39:45,280 --> 00:39:46,270 hello comma Emma. 799 00:39:46,270 --> 00:39:49,990 I hardcoded a page that has a template with a placeholder, 800 00:39:49,990 --> 00:39:53,710 and now I'm using actual logic, some code in app.py, 801 00:39:53,710 --> 00:39:59,990 to actually tell the server what to send to the browser. 802 00:39:59,990 --> 00:40:05,140 All right, any questions, then, on where we're at here? 803 00:40:05,140 --> 00:40:07,510 This is now a web application. 804 00:40:07,510 --> 00:40:11,290 Simple though it is, it's no longer just a web site. 805 00:40:11,290 --> 00:40:12,161 Yeah? 806 00:40:12,161 --> 00:40:16,760 AUDIENCE: Is what we did just better for design or for memory [INAUDIBLE]?? 807 00:40:16,760 --> 00:40:19,470 DAVID: It better for design or for memory? 808 00:40:19,470 --> 00:40:19,970 Both. 809 00:40:19,970 --> 00:40:22,160 It's definitely better for design because, truly, 810 00:40:22,160 --> 00:40:24,350 if we had a third page, fourth page, I would really 811 00:40:24,350 --> 00:40:26,150 start just resorting to copy paste. 812 00:40:26,150 --> 00:40:29,270 And as you saw with home page, often, in the head of your page, 813 00:40:29,270 --> 00:40:32,870 you might want to include some CSS files like Bootstrap or something else. 814 00:40:32,870 --> 00:40:35,360 You might want to have other information up there. 815 00:40:35,360 --> 00:40:38,992 If you had to upgrade the version of Bootstrap or you change libraries, 816 00:40:38,992 --> 00:40:40,700 so you want to change one of those lines, 817 00:40:40,700 --> 00:40:44,090 you would literally have to go into three, four, a hundred different files 818 00:40:44,090 --> 00:40:45,870 to make one simple change. 819 00:40:45,870 --> 00:40:47,240 So that's bad design. 820 00:40:47,240 --> 00:40:48,740 And in terms of memory, yes. 821 00:40:48,740 --> 00:40:52,970 Theoretically, the server, because it knows there's this common layout, 822 00:40:52,970 --> 00:40:55,632 it can theoretically do some optimizations underneath the hood. 823 00:40:55,632 --> 00:40:58,340 Flask is probably doing that, but not in the mode we're using it. 824 00:40:58,340 --> 00:41:00,260 We're using it in development mode, which 825 00:41:00,260 --> 00:41:03,830 means it's typically reloading things each time. 826 00:41:03,830 --> 00:41:07,040 Other questions on this application? 827 00:41:07,040 --> 00:41:10,210 828 00:41:10,210 --> 00:41:11,080 Anything at all? 829 00:41:11,080 --> 00:41:16,700 All right, so let me ask a question, not just in terms of the code design. 830 00:41:16,700 --> 00:41:18,880 What about the implications for privacy? 831 00:41:18,880 --> 00:41:24,430 Why is this maybe not the best design for users, how I've implemented this? 832 00:41:24,430 --> 00:41:26,470 I've used a web form, but-- 833 00:41:26,470 --> 00:41:27,305 Yeah? 834 00:41:27,305 --> 00:41:28,730 AUDIENCE: For some reason, you wanted your name. 835 00:41:28,730 --> 00:41:30,920 So these private people could just look at the URL. 836 00:41:30,920 --> 00:41:31,420 DAVID: Yeah. 837 00:41:31,420 --> 00:41:33,280 I mean, if you have a nosy sibling or roommate 838 00:41:33,280 --> 00:41:35,290 and they have access to your laptop and they just 839 00:41:35,290 --> 00:41:37,540 go trolling through your autocomplete or your history, 840 00:41:37,540 --> 00:41:40,570 like, literally what you typed into a website is going to be visible. 841 00:41:40,570 --> 00:41:43,570 Not a big deal if it's your name, but if it's your password, your credit 842 00:41:43,570 --> 00:41:45,790 card or anything else that's mildly sensitive, 843 00:41:45,790 --> 00:41:49,180 you probably don't want it ending up in the URL at all 844 00:41:49,180 --> 00:41:51,640 even if you're in incognito mode or whatnot. 845 00:41:51,640 --> 00:41:56,390 You just don't want to expose yourself or your users to that kind of risk. 846 00:41:56,390 --> 00:41:58,180 So perhaps, we can do better than that. 847 00:41:58,180 --> 00:42:00,550 And fortunately, this one is actually an easy change. 848 00:42:00,550 --> 00:42:05,740 Let me go into my index.html where my form is. 849 00:42:05,740 --> 00:42:10,510 And in my form, I can just change the method from GET to POST. 850 00:42:10,510 --> 00:42:13,150 It's still going to send key value pairs to the server, 851 00:42:13,150 --> 00:42:15,190 but it's not going to put them in the URL. 852 00:42:15,190 --> 00:42:18,495 The upside of which is that we can assuage this privacy concern, 853 00:42:18,495 --> 00:42:20,620 but I'm going to have to make one other change too. 854 00:42:20,620 --> 00:42:25,090 Because now, if I go ahead and run Flask again after making that change, 855 00:42:25,090 --> 00:42:29,570 and I now reload the form to make sure I have the latest version. 856 00:42:29,570 --> 00:42:32,410 You should be in the habit of going to View, Developer, 857 00:42:32,410 --> 00:42:35,022 View Source, or Developer Tools just to make sure 858 00:42:35,022 --> 00:42:37,480 that what you're seeing in your browser is what you intend. 859 00:42:37,480 --> 00:42:40,300 And yes, I do see what I wanted. 860 00:42:40,300 --> 00:42:41,890 Method equals POST now. 861 00:42:41,890 --> 00:42:44,620 Let me go ahead and type in David and click Submit. 862 00:42:44,620 --> 00:42:47,110 Now I get a different error. 863 00:42:47,110 --> 00:42:51,140 This one is HTTP 405, method not allowed. 864 00:42:51,140 --> 00:42:52,240 Why is that? 865 00:42:52,240 --> 00:42:56,320 Well, in my Flask application, I've only defined a couple of routes so far. 866 00:42:56,320 --> 00:42:59,840 One of which is for slash, then that worked fine. 867 00:42:59,840 --> 00:43:02,990 One of which is for /greet, and that used to work fine. 868 00:43:02,990 --> 00:43:08,540 But apparently, what Flask is doing is it only supports GET by default. 869 00:43:08,540 --> 00:43:13,750 So if I want to change this route to support different methods, I can say, 870 00:43:13,750 --> 00:43:18,920 quote unquote "POST" inside of this parameter here. 871 00:43:18,920 --> 00:43:23,830 So that now, I can actually support POST, not just GET. 872 00:43:23,830 --> 00:43:30,880 And if I now restart Flask, so Flask run, Enter, and I go back to this URL. 873 00:43:30,880 --> 00:43:33,520 Let me go back one screen to the form, reload 874 00:43:33,520 --> 00:43:35,440 the page just to make sure I have the latest 875 00:43:35,440 --> 00:43:37,023 even though nothing there has changed. 876 00:43:37,023 --> 00:43:40,630 Type David and click Submit now, now I should see hello, world. 877 00:43:40,630 --> 00:43:47,380 Notice that I'm at the greet route, but there's no mention of name 878 00:43:47,380 --> 00:43:50,260 equals anything in the URL. 879 00:43:50,260 --> 00:43:52,570 All right, so that's an interesting takeaway. 880 00:43:52,570 --> 00:43:57,380 It's a simple change, but whereas GET puts things in the URL, POST does not. 881 00:43:57,380 --> 00:43:59,620 But it still works so long as you tweak the backend 882 00:43:59,620 --> 00:44:04,210 to look as a POST request, which means look deeper in the envelope. 883 00:44:04,210 --> 00:44:06,760 It's not going to be as simple as looking at the URL itself. 884 00:44:06,760 --> 00:44:08,560 Why shouldn't we just always use POST? 885 00:44:08,560 --> 00:44:11,730 886 00:44:11,730 --> 00:44:15,990 Why not use POST everywhere? 887 00:44:15,990 --> 00:44:17,580 Any thoughts? 888 00:44:17,580 --> 00:44:21,060 Right, because it's obnoxious to be putting any information in URLs 889 00:44:21,060 --> 00:44:24,322 if you're leaving these little breadcrumbs in your history and people 890 00:44:24,322 --> 00:44:26,280 can poke around and see what you've been doing. 891 00:44:26,280 --> 00:44:29,940 892 00:44:29,940 --> 00:44:31,377 Yeah, what do you think? 893 00:44:31,377 --> 00:44:33,762 AUDIENCE: You're supposed to duplicate [INAUDIBLE].. 894 00:44:33,762 --> 00:44:37,270 895 00:44:37,270 --> 00:44:37,770 DAVID: Yeah. 896 00:44:37,770 --> 00:44:41,030 I mean, if you get rid of GET requests and put nothing in the URL, 897 00:44:41,030 --> 00:44:44,432 your history, your autocomplete, gets pretty less useful. 898 00:44:44,432 --> 00:44:47,390 Because none of the information is there for storage, so you can't just 899 00:44:47,390 --> 00:44:48,807 go through the menu and hit Enter. 900 00:44:48,807 --> 00:44:50,420 You'd have to re-fill out the form. 901 00:44:50,420 --> 00:44:52,628 And there's this other symptom that you can see here. 902 00:44:52,628 --> 00:44:55,253 Let me zoom out and let me just reload this page. 903 00:44:55,253 --> 00:44:57,170 Notice that you'll get this warning, and it'll 904 00:44:57,170 --> 00:45:01,790 look different in Safari and Firefox and Edge and Chrome here, confirm form. 905 00:45:01,790 --> 00:45:02,580 args 906 00:45:02,580 --> 00:45:06,170 So your browser might remember what your inputs were and that's great, 907 00:45:06,170 --> 00:45:07,950 but just while you're on the page. 908 00:45:07,950 --> 00:45:12,800 And this is in contrast to GET, where the state is information. 909 00:45:12,800 --> 00:45:16,195 Like, key value pairs is embedded in the URL itself. 910 00:45:16,195 --> 00:45:18,320 And if you looked at an email I sent earlier today, 911 00:45:18,320 --> 00:45:21,515 I deliberately linked to https://www.google.c 912 00:45:21,515 --> 00:45:23,120 om/search?q=what+time+is+it. 913 00:45:23,120 --> 00:45:29,210 914 00:45:29,210 --> 00:45:33,710 This is, by definition, a GET request when you click on it. 915 00:45:33,710 --> 00:45:37,100 Because it's going to grab the information, the key value pair, 916 00:45:37,100 --> 00:45:40,410 from the URL, send it to Google server, and it's just going to work. 917 00:45:40,410 --> 00:45:42,830 And the reason I sent this via email earlier was I 918 00:45:42,830 --> 00:45:46,050 wanted people to very quickly be able to check what is the current time. 919 00:45:46,050 --> 00:45:49,970 And so I can sort automate the process of creating a Google search for you, 920 00:45:49,970 --> 00:45:52,190 but that you induce when you click that link. 921 00:45:52,190 --> 00:45:57,620 If Google did not support GET, they only supported this, the best I could do 922 00:45:57,620 --> 00:46:00,410 is send you all to this URL which, unfortunately, 923 00:46:00,410 --> 00:46:02,000 has no useful information. 924 00:46:02,000 --> 00:46:05,210 I would have had to add to my email, by the way, type in the words 925 00:46:05,210 --> 00:46:07,050 what time is it. 926 00:46:07,050 --> 00:46:08,760 So it's just bad for usability. 927 00:46:08,760 --> 00:46:11,960 So there, too, we might have design when it comes to the low level code, 928 00:46:11,960 --> 00:46:15,500 but also the design when it comes to the user experience, or UX, 929 00:46:15,500 --> 00:46:17,180 as a computer scientist would call it. 930 00:46:17,180 --> 00:46:20,450 Just in terms of what you want to optimize for, ultimately. 931 00:46:20,450 --> 00:46:22,320 So GET and POST both have their roles. 932 00:46:22,320 --> 00:46:24,820 It depends on what kind of functionality you want to provide 933 00:46:24,820 --> 00:46:29,150 and what kind of sensitivity there might be around it. 934 00:46:29,150 --> 00:46:32,360 All right, any questions, then, on this, our first web application? 935 00:46:32,360 --> 00:46:35,960 Super simple, just gets someone's name and prints it back out. 936 00:46:35,960 --> 00:46:38,270 But we now have all the plumbing with which 937 00:46:38,270 --> 00:46:41,270 to create really most anything we want. 938 00:46:41,270 --> 00:46:44,058 939 00:46:44,058 --> 00:46:46,350 All right, let's go ahead and take a five minute break. 940 00:46:46,350 --> 00:46:50,190 And when we come back, we'll add to this some first year intramural sports. 941 00:46:50,190 --> 00:46:52,440 All right, so we are back. 942 00:46:52,440 --> 00:46:54,420 And recall that the last thing we just changed 943 00:46:54,420 --> 00:46:57,180 was the route to use POST instead of GET. 944 00:46:57,180 --> 00:47:00,090 So gone is my name and any value in the URL. 945 00:47:00,090 --> 00:47:06,270 But there was a subtle bug or change here that we didn't call out earlier. 946 00:47:06,270 --> 00:47:09,300 I did type David into the form and I did click Submit, 947 00:47:09,300 --> 00:47:12,690 and yet here it is saying hello comma world. 948 00:47:12,690 --> 00:47:15,730 So that seems to be broken all of a sudden, 949 00:47:15,730 --> 00:47:18,810 even though we added support for POST. 950 00:47:18,810 --> 00:47:21,030 But something must be wrong. 951 00:47:21,030 --> 00:47:23,580 Logically, it must be the case here. 952 00:47:23,580 --> 00:47:27,700 Intuitively, that if I'm seeing hello, world, that's the default value 953 00:47:27,700 --> 00:47:29,400 I gave the name variable. 954 00:47:29,400 --> 00:47:32,340 It must be that it's not seeing a key called 955 00:47:32,340 --> 00:47:36,720 name in request.args, which is this. 956 00:47:36,720 --> 00:47:39,090 Gives you access to everything after the URL. 957 00:47:39,090 --> 00:47:41,710 That's because there's this other thing we should know about, 958 00:47:41,710 --> 00:47:43,980 which is not just request.args but request.form. 959 00:47:43,980 --> 00:47:48,450 These are horribly named, but request.args is for GET requests, 960 00:47:48,450 --> 00:47:51,042 request.form is for POST requests. 961 00:47:51,042 --> 00:47:53,250 Otherwise, they're pretty much functionally the same. 962 00:47:53,250 --> 00:47:55,830 But the onus is on you, the user or the programmer, 963 00:47:55,830 --> 00:47:58,070 to make sure you're using the right one. 964 00:47:58,070 --> 00:48:00,910 So I think if we want to get rid of the world 965 00:48:00,910 --> 00:48:03,240 and actually see what I, the human, typed in, 966 00:48:03,240 --> 00:48:07,440 I think I can just change request.args to request.form. 967 00:48:07,440 --> 00:48:10,020 Still dot get, still quote unquote "name," 968 00:48:10,020 --> 00:48:14,490 and now, if I go ahead and rerun Flask in my terminal window, 969 00:48:14,490 --> 00:48:17,015 go back to my browser, go back to-- and actually, 970 00:48:17,015 --> 00:48:18,390 I won't even go back to the form. 971 00:48:18,390 --> 00:48:21,630 I will literally just reload, Command R or Control R, 972 00:48:21,630 --> 00:48:24,810 and what this warning is saying is it's going to submit 973 00:48:24,810 --> 00:48:27,240 the same information to the website. 974 00:48:27,240 --> 00:48:31,140 When I click Continue, now I should see hello comma David. 975 00:48:31,140 --> 00:48:33,420 So again, you, too, are going to encounter, probably, 976 00:48:33,420 --> 00:48:35,040 all these little subtleties. 977 00:48:35,040 --> 00:48:38,040 But if you focus on, really, the first principles of last week, 978 00:48:38,040 --> 00:48:40,920 like what it HTTP, how does it get request work, 979 00:48:40,920 --> 00:48:43,025 how does a POST request work now, you should 980 00:48:43,025 --> 00:48:45,150 have a lot of the mental building blocks with which 981 00:48:45,150 --> 00:48:47,340 to solve problems like these. 982 00:48:47,340 --> 00:48:50,580 And let me give you one other mental model, now, for what it is we're doing. 983 00:48:50,580 --> 00:48:54,900 This framework called Flask is just an example of many different frameworks 984 00:48:54,900 --> 00:48:58,500 that all implement the same paradigm, the same way of thinking 985 00:48:58,500 --> 00:49:00,720 and the same way of programming applications. 986 00:49:00,720 --> 00:49:04,170 And that's known as MVC, model view controller. 987 00:49:04,170 --> 00:49:08,670 And here's a very simple diagram that represents the process that you 988 00:49:08,670 --> 00:49:10,540 and I have been implementing thus far. 989 00:49:10,540 --> 00:49:13,530 And actually, this is more than we've been implementing thus far. 990 00:49:13,530 --> 00:49:17,362 In app.py is what a programmer would typically call the controller. 991 00:49:17,362 --> 00:49:19,320 That's the code you're writing, this are called 992 00:49:19,320 --> 00:49:23,370 business logic that makes all of the decisions, decides what to render, 993 00:49:23,370 --> 00:49:25,710 what values to show, and so forth. 994 00:49:25,710 --> 00:49:32,100 In layout.html, index.html, greet.html is the so-called view templates 995 00:49:32,100 --> 00:49:34,890 that is the visualizations that the human actually 996 00:49:34,890 --> 00:49:36,510 sees, the user interface. 997 00:49:36,510 --> 00:49:40,800 Those things are dumb, they pretty much just say plop some values here. 998 00:49:40,800 --> 00:49:43,230 All of the hard work is done in app.py. 999 00:49:43,230 --> 00:49:48,240 So controller, AKA app.py, is where your Python code generally is. 1000 00:49:48,240 --> 00:49:53,730 And in your view is where your HTML and your Jinja code, your Jinja templating, 1001 00:49:53,730 --> 00:49:57,750 the curly braces, the curly braces with percent signs, usually is. 1002 00:49:57,750 --> 00:50:01,650 We haven't added an M to MVC yet model, that's 1003 00:50:01,650 --> 00:50:04,560 going to refer to things like CSV files or databases. 1004 00:50:04,560 --> 00:50:08,355 The model, where do you keep actual data, typically long term. 1005 00:50:08,355 --> 00:50:10,230 So we'll come back to that, but this picture, 1006 00:50:10,230 --> 00:50:14,550 where you have one of these-- each of these components communicating with one 1007 00:50:14,550 --> 00:50:17,460 another is representative of how a lot of frameworks work. 1008 00:50:17,460 --> 00:50:21,030 What we're teaching today, this week, is not really specific to Python. 1009 00:50:21,030 --> 00:50:23,820 It's not really specific to Flask, even though we're using Flask. 1010 00:50:23,820 --> 00:50:25,710 It really is a very common paradigm that you 1011 00:50:25,710 --> 00:50:30,450 could implement in Java, C sharp, or bunches of other languages as well. 1012 00:50:30,450 --> 00:50:34,833 All right, so let's now pivot back to VS Code here. 1013 00:50:34,833 --> 00:50:36,750 Let me stop running Flask, and let me go ahead 1014 00:50:36,750 --> 00:50:42,160 and create a new folder altogether after closing these files here. 1015 00:50:42,160 --> 00:50:46,830 And let me go ahead and create a folder called FroshIMS, 1016 00:50:46,830 --> 00:50:50,100 representing freshman intramural sports or first year intramural sports 1017 00:50:50,100 --> 00:50:51,660 that I can now CD into. 1018 00:50:51,660 --> 00:50:54,840 And now I'm going to code an app.py. 1019 00:50:54,840 --> 00:50:58,590 And in anticipation, I'm going to create another templates directory. 1020 00:50:58,590 --> 00:51:00,490 This one in the FroshIMS folder. 1021 00:51:00,490 --> 00:51:04,590 And then in my templates directory, I'm going to create a layout.html. 1022 00:51:04,590 --> 00:51:06,720 and I'm just going to get myself started here. 1023 00:51:06,720 --> 00:51:08,460 FroshIMS will go here. 1024 00:51:08,460 --> 00:51:10,980 I'm just copying my layout from earlier because most 1025 00:51:10,980 --> 00:51:15,270 of my interesting work, this time, is now going to be, initially, in app.py. 1026 00:51:15,270 --> 00:51:16,750 So what is it we're creating? 1027 00:51:16,750 --> 00:51:20,520 So literally, the very first thing I wrote as a web application 1028 00:51:20,520 --> 00:51:24,280 20 years ago, was a site that literally looked like this. 1029 00:51:24,280 --> 00:51:26,370 So I was like a sophomore or junior at the time. 1030 00:51:26,370 --> 00:51:29,220 I'd taken CS50 and a follow-on class only. 1031 00:51:29,220 --> 00:51:31,127 I had no idea how to do web programming. 1032 00:51:31,127 --> 00:51:33,960 Neither of those two courses taught web programming back in the day. 1033 00:51:33,960 --> 00:51:36,630 So I taught myself, at the time, a language called Perl. 1034 00:51:36,630 --> 00:51:40,238 And I learned a little something about CSV files, and I sort of read enough-- 1035 00:51:40,238 --> 00:51:42,780 can't even say googled enough, because Google didn't come out 1036 00:51:42,780 --> 00:51:44,380 for a couple of years later. 1037 00:51:44,380 --> 00:51:48,670 Read enough online to figure out how to make a web application so that students 1038 00:51:48,670 --> 00:51:51,520 on campus, first years, could actually register 1039 00:51:51,520 --> 00:51:54,400 via a website for intramural sports. 1040 00:51:54,400 --> 00:51:57,400 Back in my day, you would literally fill out a piece of paper 1041 00:51:57,400 --> 00:52:00,730 and then walk it across the yard to Wigglesworth Hall, one of the dorms, 1042 00:52:00,730 --> 00:52:03,100 slide it under the dorm of the Proctor or RA, 1043 00:52:03,100 --> 00:52:05,620 and thus you were registered for sports so. 1044 00:52:05,620 --> 00:52:07,240 1996, 1997. 1045 00:52:07,240 --> 00:52:08,770 We could do better by then. 1046 00:52:08,770 --> 00:52:10,750 There was an internet, just wasn't really being 1047 00:52:10,750 --> 00:52:13,040 used much on campus or more generally. 1048 00:52:13,040 --> 00:52:16,540 So background images that repeat infinitely 1049 00:52:16,540 --> 00:52:18,850 was in vogue, apparently, at the time. 1050 00:52:18,850 --> 00:52:21,190 All of this was like images that I had to hand make 1051 00:52:21,190 --> 00:52:26,120 because we did not have the features that JavaScript and CSS nowadays have. 1052 00:52:26,120 --> 00:52:30,040 So it was really just HTML, and it was really just controller code written, 1053 00:52:30,040 --> 00:52:31,750 not in Python, but in Perl. 1054 00:52:31,750 --> 00:52:34,540 And it was really just the same building blocks 1055 00:52:34,540 --> 00:52:37,370 that we hear already today now have. 1056 00:52:37,370 --> 00:52:39,940 So we'll get rid of all of the imagery and focus more 1057 00:52:39,940 --> 00:52:42,190 on the functionality and the aesthetics, but let's see 1058 00:52:42,190 --> 00:52:45,490 if we can whip up a web application via which someone could 1059 00:52:45,490 --> 00:52:48,520 register for one such intramural sport. 1060 00:52:48,520 --> 00:52:52,210 So in app.py, me go ahead and import some familiar things now. 1061 00:52:52,210 --> 00:52:55,720 From Flask, let's import capital Flask, which 1062 00:52:55,720 --> 00:52:58,720 is that function we need to kick everything kick start everything. 1063 00:52:58,720 --> 00:53:01,900 Render templates, so we have the ability to render, that is print out, 1064 00:53:01,900 --> 00:53:04,360 those templates, and request so that we have the ability 1065 00:53:04,360 --> 00:53:07,088 to get at input from the human. 1066 00:53:07,088 --> 00:53:09,130 Let me go ahead and create the application itself 1067 00:53:09,130 --> 00:53:11,540 using this magical incantation here. 1068 00:53:11,540 --> 00:53:18,380 And then let's go ahead and define a route for slash for instance first. 1069 00:53:18,380 --> 00:53:20,260 I'm going to define a function called index. 1070 00:53:20,260 --> 00:53:22,900 But just to be clear, this function could be anything. 1071 00:53:22,900 --> 00:53:25,460 Foo, bar, baz, anything else. 1072 00:53:25,460 --> 00:53:27,520 But I tend to name them in a manner that's 1073 00:53:27,520 --> 00:53:29,260 consistent with what the route is called. 1074 00:53:29,260 --> 00:53:31,300 But you could call it anything you want, it's 1075 00:53:31,300 --> 00:53:34,840 just the function that will get called for this particular route. 1076 00:53:34,840 --> 00:53:37,090 Now, let me go ahead here and just get things started. 1077 00:53:37,090 --> 00:53:40,533 Return, render template of index.html. 1078 00:53:40,533 --> 00:53:41,950 Just keep it simple, nothing more. 1079 00:53:41,950 --> 00:53:44,860 So there's nothing really FroshIM specific about this here, 1080 00:53:44,860 --> 00:53:47,410 I just want to make sure I'm doing everything correctly. 1081 00:53:47,410 --> 00:53:49,390 Meanwhile, I've got my layout. 1082 00:53:49,390 --> 00:53:53,800 OK, let me go ahead, and in my templates directory, code a file 1083 00:53:53,800 --> 00:53:55,990 called index.html. 1084 00:53:55,990 --> 00:54:02,290 And let's just do extends layout.html at the top 1085 00:54:02,290 --> 00:54:04,390 just so that we get benefit from that template. 1086 00:54:04,390 --> 00:54:06,250 And down here, I'm just going to say to do. 1087 00:54:06,250 --> 00:54:09,250 Just so that I have something going on visually to make sure 1088 00:54:09,250 --> 00:54:10,690 I've not screwed up yet. 1089 00:54:10,690 --> 00:54:14,020 In my FroshIMS directory, let me do Flask run. 1090 00:54:14,020 --> 00:54:17,200 Let me now go back to my previous URL, which used to be my hello example. 1091 00:54:17,200 --> 00:54:21,850 But now, I'm serving up the FroshIM site. 1092 00:54:21,850 --> 00:54:23,590 Oh, and I'm seeing nothing. 1093 00:54:23,590 --> 00:54:26,860 That's because I screwed up accidentally. 1094 00:54:26,860 --> 00:54:30,090 What did I do wrong in index.html? 1095 00:54:30,090 --> 00:54:34,580 1096 00:54:34,580 --> 00:54:35,600 What am I doing wrong? 1097 00:54:35,600 --> 00:54:38,468 This file extends layout.html, but-- 1098 00:54:38,468 --> 00:54:40,010 AUDIENCE: You left out the block tag? 1099 00:54:40,010 --> 00:54:40,510 DAVID: Yeah. 1100 00:54:40,510 --> 00:54:44,900 I forgot to tell Flask what to plug into that layout. 1101 00:54:44,900 --> 00:54:49,040 So I just need to say block body, and then in here, I can just say to do 1102 00:54:49,040 --> 00:54:51,080 or whatever I want to eventually get around to. 1103 00:54:51,080 --> 00:54:52,310 Then end the block. 1104 00:54:52,310 --> 00:54:53,990 Let me end this tag here. 1105 00:54:53,990 --> 00:54:56,330 OK, so now it looks ugly, more cryptic. 1106 00:54:56,330 --> 00:54:59,210 But this is, again, the essence of doing templating. 1107 00:54:59,210 --> 00:55:03,340 Let me now restart Flask up here, let me go back to the page. 1108 00:55:03,340 --> 00:55:03,972 Let me reload. 1109 00:55:03,972 --> 00:55:05,930 Crossing my fingers this time, and there we go. 1110 00:55:05,930 --> 00:55:06,320 To do. 1111 00:55:06,320 --> 00:55:08,480 So it's not the application I want, but at least I 1112 00:55:08,480 --> 00:55:10,868 know I have some of the plumbing there by default. 1113 00:55:10,868 --> 00:55:13,160 All right, so if I want the user to be able to register 1114 00:55:13,160 --> 00:55:15,350 for one of these sports, let's enhance, now, 1115 00:55:15,350 --> 00:55:18,290 index.html to actually have a form that's 1116 00:55:18,290 --> 00:55:22,050 maybe got a dropdown menu for all of the sports for which you can register. 1117 00:55:22,050 --> 00:55:24,230 So let me go into this template here. 1118 00:55:24,230 --> 00:55:27,410 And instead of to do, let's go ahead and give myself, 1119 00:55:27,410 --> 00:55:31,160 how about an H1 tag that just says register so the user knows what it is 1120 00:55:31,160 --> 00:55:31,970 they're looking at. 1121 00:55:31,970 --> 00:55:35,270 How about a form tag that's going to use POST, 1122 00:55:35,270 --> 00:55:38,450 just because it's not really necessary to put this kind of information 1123 00:55:38,450 --> 00:55:39,530 in the URL. 1124 00:55:39,530 --> 00:55:42,260 The action for that, how about we plan to create 1125 00:55:42,260 --> 00:55:47,210 a register route so that we're sending information from to a register route. 1126 00:55:47,210 --> 00:55:48,770 So we'll have to come back to that. 1127 00:55:48,770 --> 00:55:54,650 In here, let me go ahead and create, how about an input with autocomplete 1128 00:55:54,650 --> 00:55:58,020 equals off, auto focus on. 1129 00:55:58,020 --> 00:56:00,062 How about a name equals name, because I'm 1130 00:56:00,062 --> 00:56:03,020 going to ask the student for their name using placeholder text of quote 1131 00:56:03,020 --> 00:56:03,867 unquote "name." 1132 00:56:03,867 --> 00:56:05,450 And the type of this box will be text. 1133 00:56:05,450 --> 00:56:07,610 So this is pretty much identical to before. 1134 00:56:07,610 --> 00:56:11,060 But if you've not seen this yet, let's create a select menu, 1135 00:56:11,060 --> 00:56:13,280 a so-called dropdown menu in HTML. 1136 00:56:13,280 --> 00:56:16,790 And maybe the first option I want to be in there 1137 00:56:16,790 --> 00:56:20,570 is going to be, oh, how about the current three 1138 00:56:20,570 --> 00:56:27,560 sports for the fall, which are basketball, and another option 1139 00:56:27,560 --> 00:56:30,140 is going to be soccer, and a third option is 1140 00:56:30,140 --> 00:56:35,700 going to be ultimate frisbee for first year intramurals right now. 1141 00:56:35,700 --> 00:56:37,160 So I've got those three options. 1142 00:56:37,160 --> 00:56:38,300 I've got my form. 1143 00:56:38,300 --> 00:56:42,650 I haven't implemented my route yet, but this feels like a good time 1144 00:56:42,650 --> 00:56:45,920 to go back now and check if my form has reloaded. 1145 00:56:45,920 --> 00:56:48,658 So let me go ahead and stop and start Flask. 1146 00:56:48,658 --> 00:56:51,200 You'll see there's ways to automate the process of restarting 1147 00:56:51,200 --> 00:56:53,360 the server that we'll do for you for problem set nine, 1148 00:56:53,360 --> 00:56:55,070 so you don't have to keep stopping Flask. 1149 00:56:55,070 --> 00:56:59,060 Let me reload my index route and OK, it's not that pretty. 1150 00:56:59,060 --> 00:57:01,220 It's not though, maybe-- 1151 00:57:01,220 --> 00:57:02,000 nor was this. 1152 00:57:02,000 --> 00:57:04,070 But it now has at least some functionality 1153 00:57:04,070 --> 00:57:07,160 where I can type in my name and then type in the sport. 1154 00:57:07,160 --> 00:57:09,740 Now, I might be biasing people toward basketball. 1155 00:57:09,740 --> 00:57:14,210 Like UX wise, user experience wise, it's obnoxious to precheck 1156 00:57:14,210 --> 00:57:15,810 basketball but not the others. 1157 00:57:15,810 --> 00:57:17,810 So there's some little tweaks we can make there. 1158 00:57:17,810 --> 00:57:20,060 Let me go back into index.html. 1159 00:57:20,060 --> 00:57:26,348 Let me create an empty option up here that, technically, this option is not 1160 00:57:26,348 --> 00:57:27,890 going to have the name of any sports. 1161 00:57:27,890 --> 00:57:30,348 But it's just going to have a word I want the human to see, 1162 00:57:30,348 --> 00:57:34,860 so I'm actually going to disable this option and make it selected by default. 1163 00:57:34,860 --> 00:57:37,250 But I'm going to say sport up here. 1164 00:57:37,250 --> 00:57:40,730 And there's different ways to do this, this is just one way of creating, 1165 00:57:40,730 --> 00:57:42,470 essentially, a-- 1166 00:57:42,470 --> 00:57:43,430 whoops, option. 1167 00:57:43,430 --> 00:57:44,660 Yep, that looks right. 1168 00:57:44,660 --> 00:57:47,000 Creating a placeholder sports so that the user 1169 00:57:47,000 --> 00:57:49,100 sees something in the dropdown. 1170 00:57:49,100 --> 00:57:52,170 Let me go ahead and restart Flask, reload the page, 1171 00:57:52,170 --> 00:57:54,170 and now it's just going to be marginally better. 1172 00:57:54,170 --> 00:57:56,360 Now you see sport that's checked by default, 1173 00:57:56,360 --> 00:57:59,330 but you have to check one of these other ones ultimately. 1174 00:57:59,330 --> 00:58:00,720 All right, so that's pretty good. 1175 00:58:00,720 --> 00:58:02,930 So let me now type in David. 1176 00:58:02,930 --> 00:58:05,360 I'll register for ultimate frisbee. 1177 00:58:05,360 --> 00:58:08,750 OK, I definitely forgot something. 1178 00:58:08,750 --> 00:58:09,540 Submit button. 1179 00:58:09,540 --> 00:58:10,940 So let's add that. 1180 00:58:10,940 --> 00:58:15,020 All right, so input type equals submit. 1181 00:58:15,020 --> 00:58:16,340 All right, let's put that in. 1182 00:58:16,340 --> 00:58:19,010 Restart Flask, reload. 1183 00:58:19,010 --> 00:58:19,783 Getting better. 1184 00:58:19,783 --> 00:58:21,200 Submit could be a little prettier. 1185 00:58:21,200 --> 00:58:25,730 Recall that we can change some of these HTTP-- these HTML attributes. 1186 00:58:25,730 --> 00:58:27,890 The value of this button should be register, maybe, 1187 00:58:27,890 --> 00:58:29,480 just to make things a little prettier. 1188 00:58:29,480 --> 00:58:32,695 Let me now reload the page and register. 1189 00:58:32,695 --> 00:58:35,570 All right, so now we really have the beginnings of the user interface 1190 00:58:35,570 --> 00:58:39,980 that I created some years ago to let people actually register for the sport. 1191 00:58:39,980 --> 00:58:43,880 So let's go, now, and create maybe the other route that we might need. 1192 00:58:43,880 --> 00:58:44,930 Let me go into app.py. 1193 00:58:44,930 --> 00:58:47,925 And in here, if we want to allow the user to register, 1194 00:58:47,925 --> 00:58:51,050 let's do a little bit of error checking which I promised we'd come back to. 1195 00:58:51,050 --> 00:58:52,850 What could the user do wrong? 1196 00:58:52,850 --> 00:58:55,040 Because assume that they will. 1197 00:58:55,040 --> 00:58:56,870 One, they might not type their name. 1198 00:58:56,870 --> 00:58:58,743 Two, they might not choose a sport. 1199 00:58:58,743 --> 00:59:00,410 So they might just submit an empty form. 1200 00:59:00,410 --> 00:59:02,540 So that's two things we could check for, just 1201 00:59:02,540 --> 00:59:05,960 so that we're not scoring bogus entries in our database, ultimately. 1202 00:59:05,960 --> 00:59:09,590 So let's create another route called greet, /greet. 1203 00:59:09,590 --> 00:59:12,740 And then in this route, let's create a function called greet 1204 00:59:12,740 --> 00:59:14,900 but can be called anything we want. 1205 00:59:14,900 --> 00:59:18,293 And then let's go ahead, and in the greet function, let's go ahead 1206 00:59:18,293 --> 00:59:19,460 and validate the submission. 1207 00:59:19,460 --> 00:59:21,590 So a little comment to myself here. 1208 00:59:21,590 --> 00:59:30,270 How about if there is not a request.form GET name value, 1209 00:59:30,270 --> 00:59:32,450 so that is if that function returns nothing, 1210 00:59:32,450 --> 00:59:36,300 like quote unquote, or the special word none in Python. 1211 00:59:36,300 --> 00:59:47,280 Or request.form.get"sport" not in quote unquote, what were they? 1212 00:59:47,280 --> 00:59:54,360 Basketball, the other one was soccer, and the last was ultimate frisbee. 1213 00:59:54,360 --> 00:59:58,200 Getting a little long, but notice what I'm-- the question I'm asking. 1214 00:59:58,200 --> 01:00:01,290 If the user did not give us a name, that is, 1215 01:00:01,290 --> 01:00:03,910 if this function returns the equivalent of false, 1216 01:00:03,910 --> 01:00:07,830 which is, quote unquote, or literally none if there's no such parameter. 1217 01:00:07,830 --> 01:00:14,490 Or if the sport the user provided is not some value in basketball, soccer, 1218 01:00:14,490 --> 01:00:18,300 or ultimate frisbee, which I've defined as a Python list, then let's go ahead 1219 01:00:18,300 --> 01:00:19,890 and just yell at the user in some way. 1220 01:00:19,890 --> 01:00:25,200 Let's return render template of failure.html. 1221 01:00:25,200 --> 01:00:28,450 And that's just going to be some error message inside of that file. 1222 01:00:28,450 --> 01:00:30,990 Otherwise, if they get this far, let's go ahead 1223 01:00:30,990 --> 01:00:34,350 and confirm registration by just returning-- whoops, 1224 01:00:34,350 --> 01:00:40,420 returning render template quote unquote "success" dot HTML. 1225 01:00:40,420 --> 01:00:42,700 All right, so a couple quick things to do. 1226 01:00:42,700 --> 01:00:47,350 Let me first go in and in my templates directory, 1227 01:00:47,350 --> 01:00:50,530 let's create this failure.html file. 1228 01:00:50,530 --> 01:00:53,430 And this is just meant to be a message to the user 1229 01:00:53,430 --> 01:00:56,500 that they fail to provide the information correctly. 1230 01:00:56,500 --> 01:00:59,280 So let me go ahead and in failure.html. 1231 01:00:59,280 --> 01:01:02,250 not repeat my past mistake. 1232 01:01:02,250 --> 01:01:07,140 So let me extend layout.html and in the block body, you are not registered. 1233 01:01:07,140 --> 01:01:10,140 I'll just yell at them like that so that they know something went wrong. 1234 01:01:10,140 --> 01:01:14,760 And then let me create one other file called success.html, that 1235 01:01:14,760 --> 01:01:17,143 similarly is mostly just Jinja syntax. 1236 01:01:17,143 --> 01:01:19,560 And I'm just going to say for now, even though they're not 1237 01:01:19,560 --> 01:01:22,140 technically registered in any database, you are registered. 1238 01:01:22,140 --> 01:01:24,270 That's what we mean by success. 1239 01:01:24,270 --> 01:01:27,450 All right, so let me go ahead, and back in my FroshIMS, 1240 01:01:27,450 --> 01:01:29,370 directory run Flask run. 1241 01:01:29,370 --> 01:01:31,560 Let me go back to the form and reload. 1242 01:01:31,560 --> 01:01:33,150 Should look the same. 1243 01:01:33,150 --> 01:01:36,120 All right, so now let me not cooperate and just 1244 01:01:36,120 --> 01:01:39,300 immediately click Register impatiently. 1245 01:01:39,300 --> 01:01:42,960 OK, what did I do wrong. 1246 01:01:42,960 --> 01:01:47,008 Register-- oh, I'm confusing our two examples. 1247 01:01:47,008 --> 01:01:48,300 All right, I spotted the error. 1248 01:01:48,300 --> 01:01:49,133 What did I do wrong? 1249 01:01:49,133 --> 01:01:51,600 1250 01:01:51,600 --> 01:01:54,480 Unintentional. 1251 01:01:54,480 --> 01:01:58,050 There's where I am, what did I actually invent over here? 1252 01:01:58,050 --> 01:02:01,910 1253 01:02:01,910 --> 01:02:05,140 Where did I screw up? 1254 01:02:05,140 --> 01:02:06,800 Anyone? 1255 01:02:06,800 --> 01:02:08,050 AUDIENCE: Register, not greet. 1256 01:02:08,050 --> 01:02:08,758 DAVID: Thank you. 1257 01:02:08,758 --> 01:02:09,850 So register, not greet. 1258 01:02:09,850 --> 01:02:12,970 I had last example on my mind, so the route should be register. 1259 01:02:12,970 --> 01:02:16,360 Ironically, the function could be greet, because that actually doesn't matter. 1260 01:02:16,360 --> 01:02:20,030 But to keep ourselves sane, let's use the one and the same words there. 1261 01:02:20,030 --> 01:02:22,457 Let me go ahead now and start Flask as intended. 1262 01:02:22,457 --> 01:02:24,790 Let me reload the form just to make sure all is working. 1263 01:02:24,790 --> 01:02:29,140 Now, let me not cooperate and be a bad user, clicking register-- 1264 01:02:29,140 --> 01:02:30,220 oh my God. 1265 01:02:30,220 --> 01:02:32,890 OK, other unintended mistake. 1266 01:02:32,890 --> 01:02:35,120 But this one we've seen before. 1267 01:02:35,120 --> 01:02:37,960 Notice that by default, route only support GET. 1268 01:02:37,960 --> 01:02:40,960 So if I want to specifically support POST, 1269 01:02:40,960 --> 01:02:47,710 I have to pass in, by a methods parameter, a list of allowed route 1270 01:02:47,710 --> 01:02:50,590 methods that could be GET comma POST, but if I 1271 01:02:50,590 --> 01:02:54,460 don't have no need for a GET in this context, I can just do POST. 1272 01:02:54,460 --> 01:02:56,980 All right, now let's do this one last time. 1273 01:02:56,980 --> 01:02:59,680 Reload the form to make sure everything's OK, click Register, 1274 01:02:59,680 --> 01:03:01,433 and you are not registered. 1275 01:03:01,433 --> 01:03:02,350 So it's catching that. 1276 01:03:02,350 --> 01:03:04,767 All right, let me go ahead and at least give them my name. 1277 01:03:04,767 --> 01:03:05,500 Register. 1278 01:03:05,500 --> 01:03:06,550 You are not registered. 1279 01:03:06,550 --> 01:03:11,900 Fine, I'm going to go ahead and be David with ultimate frisbee register. 1280 01:03:11,900 --> 01:03:14,260 Huh. 1281 01:03:14,260 --> 01:03:15,640 OK. 1282 01:03:15,640 --> 01:03:20,780 What should I-- what did I mean to do here? 1283 01:03:20,780 --> 01:03:22,810 All right, so let's figure this out. 1284 01:03:22,810 --> 01:03:26,950 How to debug something like this, which is my third and final unintended, 1285 01:03:26,950 --> 01:03:29,320 unforced error? 1286 01:03:29,320 --> 01:03:32,590 How can we go about troubleshooting this? 1287 01:03:32,590 --> 01:03:35,440 Turn this into the teachable moment. 1288 01:03:35,440 --> 01:03:38,020 All right, well first, some safety checks. 1289 01:03:38,020 --> 01:03:39,610 What did I actually submit? 1290 01:03:39,610 --> 01:03:42,760 Let me go ahead and view page source, a good rule of thumb. 1291 01:03:42,760 --> 01:03:45,320 Look at the HTML that you actually sent to the user. 1292 01:03:45,320 --> 01:03:49,490 So here, I have an input with a name name. 1293 01:03:49,490 --> 01:03:51,950 So that's what I intended, that looks OK. 1294 01:03:51,950 --> 01:03:54,790 Ah, I see it already, even though you, if you've never 1295 01:03:54,790 --> 01:03:58,030 used a select menu, you might not know what, apparently, 1296 01:03:58,030 --> 01:04:04,150 is missing from here that I did have for my text input. 1297 01:04:04,150 --> 01:04:07,705 Just intuitively, logically. 1298 01:04:07,705 --> 01:04:09,580 What's going through my head, embarrassingly, 1299 01:04:09,580 --> 01:04:13,930 is, all right, if my form thinks that it's missing a name or a sport, 1300 01:04:13,930 --> 01:04:17,710 how did I create a situation in which name is blank or sport is blank? 1301 01:04:17,710 --> 01:04:19,720 Well, name, I don't think it's going to be blank 1302 01:04:19,720 --> 01:04:23,500 because I explicitly gave this text field a name name 1303 01:04:23,500 --> 01:04:25,210 and that did work last time. 1304 01:04:25,210 --> 01:04:28,660 I've now given a second input in the form of the select menu. 1305 01:04:28,660 --> 01:04:35,350 But what seems to be missing here that I'm assuming exists here? 1306 01:04:35,350 --> 01:04:38,620 It's just a dumb mistake I made. 1307 01:04:38,620 --> 01:04:41,686 What might be missing here? 1308 01:04:41,686 --> 01:04:45,790 If request.form gives you all of the inputs that the user might 1309 01:04:45,790 --> 01:04:48,790 have typed in, let me go into my actual code 1310 01:04:48,790 --> 01:04:52,690 here in my form and name equals sport. 1311 01:04:52,690 --> 01:04:54,710 I just didn't give a name to that input. 1312 01:04:54,710 --> 01:04:56,890 So it exists, and the browser doesn't care. 1313 01:04:56,890 --> 01:04:58,723 It's still going to display the form to you, 1314 01:04:58,723 --> 01:05:02,450 it just hasn't given it a unique name to actually transmit to the server. 1315 01:05:02,450 --> 01:05:04,790 So now, if I'm not going to put my foot in my mouth, 1316 01:05:04,790 --> 01:05:06,980 I think that's what I did wrong. 1317 01:05:06,980 --> 01:05:08,950 And again, my process for figuring that out 1318 01:05:08,950 --> 01:05:11,282 was looking at my code, thinking through logically, 1319 01:05:11,282 --> 01:05:12,490 is this right, is this right? 1320 01:05:12,490 --> 01:05:14,660 No, I was missing the name there. 1321 01:05:14,660 --> 01:05:17,620 So let's run Flask, let's reload the form 1322 01:05:17,620 --> 01:05:22,180 just to make sure it's all defaults again, type in my name and type 1323 01:05:22,180 --> 01:05:26,680 in ultimate frisbee, crossing my fingers extra hard this time. 1324 01:05:26,680 --> 01:05:27,470 And there. 1325 01:05:27,470 --> 01:05:28,337 You are registered. 1326 01:05:28,337 --> 01:05:29,170 So I can emphasize-- 1327 01:05:29,170 --> 01:05:30,903 I did not intend to screw up in that way, 1328 01:05:30,903 --> 01:05:33,070 but that's exactly the right kind of thought process 1329 01:05:33,070 --> 01:05:34,390 to diagnose issues like this. 1330 01:05:34,390 --> 01:05:38,260 Go back to the basics, go back to what HTTP and what HTML forms are all about, 1331 01:05:38,260 --> 01:05:40,670 and just rule things in and out. 1332 01:05:40,670 --> 01:05:43,420 There's only a finite number of ways I could have screwed that up. 1333 01:05:43,420 --> 01:05:44,292 Yeah? 1334 01:05:44,292 --> 01:05:45,648 AUDIENCE: Are you [INAUDIBLE]. 1335 01:05:45,648 --> 01:05:47,820 1336 01:05:47,820 --> 01:05:49,320 DAVID: Excuse-- say a little louder? 1337 01:05:49,320 --> 01:05:53,220 AUDIENCE: I don't understand why name equals sport [INAUDIBLE].. 1338 01:05:53,220 --> 01:05:55,870 DAVID: Why did name equal sport address the problem? 1339 01:05:55,870 --> 01:05:58,110 Well, let's first go back to the HTML. 1340 01:05:58,110 --> 01:06:05,410 Previously, it was just the reality that I had this user input dropdown menu, 1341 01:06:05,410 --> 01:06:06,840 but I never gave it a name. 1342 01:06:06,840 --> 01:06:10,170 But names, or more generally, key value pairs, 1343 01:06:10,170 --> 01:06:13,450 is how information is sent from a form to the server. 1344 01:06:13,450 --> 01:06:18,660 So if there's no name, there's no key to send, even if the human types a value. 1345 01:06:18,660 --> 01:06:22,320 It would be like nothing equals ultimate frisbee, and that just doesn't work. 1346 01:06:22,320 --> 01:06:24,670 The browser is just not going to send it. 1347 01:06:24,670 --> 01:06:30,570 However, in app.py, I was naively assuming that in my requests form, 1348 01:06:30,570 --> 01:06:33,300 there would be a name called quote unquote "sport." 1349 01:06:33,300 --> 01:06:35,940 It could have been anything, but I was assuming it was sport. 1350 01:06:35,940 --> 01:06:37,770 But I never told the form that. 1351 01:06:37,770 --> 01:06:41,260 And if I really wanted to dig in, we could do a little something more. 1352 01:06:41,260 --> 01:06:44,250 Let me go back to the way it was a moment ago. 1353 01:06:44,250 --> 01:06:48,040 Let me get rid of the name of the sport dropdown menu. 1354 01:06:48,040 --> 01:06:53,220 Let me rerun Flask down here and reload the form itself 1355 01:06:53,220 --> 01:06:55,650 after it finishes being served. 1356 01:06:55,650 --> 01:06:56,820 And now, let me do this. 1357 01:06:56,820 --> 01:07:01,515 View Developer Tools, and then let me watch the Network tab, which recall, 1358 01:07:01,515 --> 01:07:03,390 we played around with a little bit last week. 1359 01:07:03,390 --> 01:07:06,572 And we also played around with Curl, which let us see the HTTP requests. 1360 01:07:06,572 --> 01:07:08,280 Here's another-- here's what I would have 1361 01:07:08,280 --> 01:07:11,650 done if I still wasn't seeing the error and was really embarrassed on stage. 1362 01:07:11,650 --> 01:07:15,750 I would have typed in my name as before, I would have chosen ultimate frisbee. 1363 01:07:15,750 --> 01:07:17,490 I would have clicked register. 1364 01:07:17,490 --> 01:07:21,480 And now, I would have looked at the HTTP request. 1365 01:07:21,480 --> 01:07:23,580 And I would click on Register here. 1366 01:07:23,580 --> 01:07:27,180 And just like we did last week, I would go down to the request down here. 1367 01:07:27,180 --> 01:07:29,910 And there's a whole lot of stuff that we can typically ignore. 1368 01:07:29,910 --> 01:07:33,030 But here, let me zoom in, way at the bottom, 1369 01:07:33,030 --> 01:07:35,370 what Chrome's developer tools are doing for me, 1370 01:07:35,370 --> 01:07:38,380 it's showing me all of the form data that was submitted. 1371 01:07:38,380 --> 01:07:40,950 So this really would have been my telltale clue. 1372 01:07:40,950 --> 01:07:44,220 I'm just not sending the sport, even if the human typed it in. 1373 01:07:44,220 --> 01:07:46,230 And logically, because I've done this before, 1374 01:07:46,230 --> 01:07:49,170 that must mean I didn't give the thing a name. 1375 01:07:49,170 --> 01:07:50,340 But another good tool. 1376 01:07:50,340 --> 01:07:53,610 Like good programmers, web developers are using these kinds of tools 1377 01:07:53,610 --> 01:07:54,660 all the time. 1378 01:07:54,660 --> 01:07:56,398 They're not writing bug-free code. 1379 01:07:56,398 --> 01:07:57,690 That's not the point to get to. 1380 01:07:57,690 --> 01:08:00,780 The point to get to is being a good diagnostician, 1381 01:08:00,780 --> 01:08:02,790 I would say, in these cases. 1382 01:08:02,790 --> 01:08:07,790 OK, other questions on this? 1383 01:08:07,790 --> 01:08:09,050 Yeah. 1384 01:08:09,050 --> 01:08:14,390 AUDIENCE: What if you want to edit one HTML in CSS, [INAUDIBLE].. 1385 01:08:14,390 --> 01:08:16,682 DAVID: I'm sorry, a little bit louder? 1386 01:08:16,682 --> 01:08:19,250 AUDIENCE: If you want to edit in CSS or anything, 1387 01:08:19,250 --> 01:08:23,660 in HTML, once you have to fix the template, how do you that? 1388 01:08:23,660 --> 01:08:27,770 DAVID: So how would you edit CSS if you have these templates? 1389 01:08:27,770 --> 01:08:30,080 That process we'll actually see before long. 1390 01:08:30,080 --> 01:08:31,705 It's almost going to be the exact same. 1391 01:08:31,705 --> 01:08:34,788 Just to give you a teaser for this, and you'll do this in the problem set, 1392 01:08:34,788 --> 01:08:37,640 but we'll give you some distribution code to automate this process. 1393 01:08:37,640 --> 01:08:40,100 You can absolutely still do something like this. 1394 01:08:40,100 --> 01:08:44,899 Link href equals quote unquote "styles" dot 1395 01:08:44,899 --> 01:08:49,609 CSS rel equals style sheet, that's one of the techniques we showed last week. 1396 01:08:49,609 --> 01:08:53,660 The only difference today, using Flask, is that all of your static files, 1397 01:08:53,660 --> 01:08:56,279 by convention, should go in your static folder. 1398 01:08:56,279 --> 01:08:58,310 So the change you would make in your layout 1399 01:08:58,310 --> 01:09:02,240 would be to say that styles dot CSS is in your static folder. 1400 01:09:02,240 --> 01:09:06,229 And then, if I go into my FroshIMS directory, 1401 01:09:06,229 --> 01:09:08,569 I can create a static folder. 1402 01:09:08,569 --> 01:09:11,060 I can CD into it, nothing's there by default. 1403 01:09:11,060 --> 01:09:14,000 But if I now code a file called styles.css, 1404 01:09:14,000 --> 01:09:17,060 I could now do something like this body. 1405 01:09:17,060 --> 01:09:28,220 And in here, I could say background color, say FF0000 to make it red. 1406 01:09:28,220 --> 01:09:32,450 Let me go ahead now and restart Flask in the FroshIMS directory. 1407 01:09:32,450 --> 01:09:35,060 Cross my fingers because I'm doing this on the fly. 1408 01:09:35,060 --> 01:09:38,399 Go back to my form and reload. 1409 01:09:38,399 --> 01:09:41,990 Voila, now we've tied together last week's stuff as well. 1410 01:09:41,990 --> 01:09:45,092 If I answered the right question? 1411 01:09:45,092 --> 01:09:49,440 AUDIENCE: [INAUDIBLE] change one page and not the other. 1412 01:09:49,440 --> 01:09:52,440 DAVID: If you want to change one page and not the other in terms of CSS? 1413 01:09:52,440 --> 01:09:53,250 AUDIENCE: Yes. 1414 01:09:53,250 --> 01:09:54,360 DAVID: That depends. 1415 01:09:54,360 --> 01:09:59,190 In that case, you might want to have different CSS files for each page 1416 01:09:59,190 --> 01:10:00,390 if they're different. 1417 01:10:00,390 --> 01:10:04,620 You could use different classes in one template than you did in the other. 1418 01:10:04,620 --> 01:10:06,040 There's different ways to do that. 1419 01:10:06,040 --> 01:10:09,990 You could even have a placeholder in your layout 1420 01:10:09,990 --> 01:10:14,460 that allows you to plug in the URL of a specific style 1421 01:10:14,460 --> 01:10:15,900 sheet in your individual files. 1422 01:10:15,900 --> 01:10:18,670 But that starts to get more complicated quickly. 1423 01:10:18,670 --> 01:10:20,410 So in short, you can absolutely do it. 1424 01:10:20,410 --> 01:10:24,180 But typically, I would say most websites try not 1425 01:10:24,180 --> 01:10:25,890 to use different style Sheets per page. 1426 01:10:25,890 --> 01:10:28,560 They reuse the styles as much as they can. 1427 01:10:28,560 --> 01:10:30,810 All right, let me go ahead and revert this real quick. 1428 01:10:30,810 --> 01:10:33,750 And let's start to add a little bit more functionality here. 1429 01:10:33,750 --> 01:10:36,630 I'm going to go ahead and just remove the static folder just so as 1430 01:10:36,630 --> 01:10:38,400 to not complicate things just yet. 1431 01:10:38,400 --> 01:10:41,490 And let's go ahead and just play around with a different user interface 1432 01:10:41,490 --> 01:10:42,090 mechanism. 1433 01:10:42,090 --> 01:10:45,503 In my form here, the dropdown menu is perfectly fine. 1434 01:10:45,503 --> 01:10:46,420 Nothing wrong with it. 1435 01:10:46,420 --> 01:10:49,650 But suppose that I wanted to change it to checkboxes instead. 1436 01:10:49,650 --> 01:10:53,670 Maybe I want students to be able to register for multiple sports instead. 1437 01:10:53,670 --> 01:10:57,060 Well, it might make sense to clean this up in a couple of ways. 1438 01:10:57,060 --> 01:10:57,810 And let's do this. 1439 01:10:57,810 --> 01:11:03,000 Before we even get into the checkboxes, there's one subtle bad design here. 1440 01:11:03,000 --> 01:11:07,450 Notice that I've hardcoded basketball, soccer, and ultimate frisbee here. 1441 01:11:07,450 --> 01:11:11,830 And if you recall, in app.py, I also enumerated all three of those here. 1442 01:11:11,830 --> 01:11:15,170 And any time you see copy paste or the equivalent thereof, 1443 01:11:15,170 --> 01:11:16,840 feels like we could do better. 1444 01:11:16,840 --> 01:11:18,640 So what if I instead do this. 1445 01:11:18,640 --> 01:11:22,950 What if I instead give myself a global variable of Sports, 1446 01:11:22,950 --> 01:11:25,350 I'll capitalize the word just to connote that it's 1447 01:11:25,350 --> 01:11:29,400 meant to be constant even though Python does not have constants, per se. 1448 01:11:29,400 --> 01:11:31,980 The first sport will be basketball. 1449 01:11:31,980 --> 01:11:33,960 The second will be soccer. 1450 01:11:33,960 --> 01:11:38,160 The third will be ultimate frisbee. 1451 01:11:38,160 --> 01:11:42,180 Now I have one convenient place to store all of my sports 1452 01:11:42,180 --> 01:11:44,700 if it changes next semester or next year or whatnot. 1453 01:11:44,700 --> 01:11:46,710 But notice what I could do to. 1454 01:11:46,710 --> 01:11:48,340 I could now do something like this. 1455 01:11:48,340 --> 01:11:52,350 Let me pass into my index template a variable 1456 01:11:52,350 --> 01:11:56,700 called sports that's equal to that global variable sports. 1457 01:11:56,700 --> 01:12:00,030 Let me go into my index now, and this is really, now, 1458 01:12:00,030 --> 01:12:04,020 going to hint at the power of templating and Jinja, in this case here. 1459 01:12:04,020 --> 01:12:07,690 Let me go ahead and get rid of all three of these hard coded options 1460 01:12:07,690 --> 01:12:12,570 and let me show you some slightly different syntax for sport, in sports. 1461 01:12:12,570 --> 01:12:15,090 Then end for. 1462 01:12:15,090 --> 01:12:17,110 We've not seen this end for syntax. 1463 01:12:17,110 --> 01:12:19,930 There's like end block syntax, but it's as simple as that. 1464 01:12:19,930 --> 01:12:23,190 So you have a start and an end to your block without indentation mattering. 1465 01:12:23,190 --> 01:12:24,630 Watch what I can do here. 1466 01:12:24,630 --> 01:12:30,720 Option curly brace sport close curly brace. 1467 01:12:30,720 --> 01:12:32,070 Let me save that. 1468 01:12:32,070 --> 01:12:35,220 Let me go back into my terminal window, do Flask run. 1469 01:12:35,220 --> 01:12:38,400 And if I didn't mess up here, let me go back to this. 1470 01:12:38,400 --> 01:12:41,040 The red's going to go away because I deleted my CSS. 1471 01:12:41,040 --> 01:12:44,070 And now I still have a sport dropdown and all of those sports 1472 01:12:44,070 --> 01:12:45,010 are still there. 1473 01:12:45,010 --> 01:12:46,590 I can make one more improvement now. 1474 01:12:46,590 --> 01:12:49,540 I don't need to mention these same sports manually in app.py. 1475 01:12:49,540 --> 01:12:53,910 I can now just say if the user's inputed sport is not 1476 01:12:53,910 --> 01:12:57,308 in my global variable, sports, and ask the same question. 1477 01:12:57,308 --> 01:12:59,100 And this is really handy because if there's 1478 01:12:59,100 --> 01:13:03,240 another sport, for instance, that gets added, like say football, 1479 01:13:03,240 --> 01:13:06,160 all I have to do is change my global variable. 1480 01:13:06,160 --> 01:13:09,780 And if I reload the form now and look in the dropdown, boom, 1481 01:13:09,780 --> 01:13:11,970 now I have support for a fourth sport. 1482 01:13:11,970 --> 01:13:13,660 And I can keep adding and adding there. 1483 01:13:13,660 --> 01:13:17,250 So here's where templating starts to get really powerful in that 1484 01:13:17,250 --> 01:13:22,710 now, in this template, I'm using Jinja's for loop syntax, which 1485 01:13:22,710 --> 01:13:25,200 is almost identical to Python here, except you 1486 01:13:25,200 --> 01:13:28,500 need the curly brace and the percent sign and you need the weird ending 1487 01:13:28,500 --> 01:13:29,370 and for. 1488 01:13:29,370 --> 01:13:31,050 But it's the same idea as in Python. 1489 01:13:31,050 --> 01:13:35,310 Iterating over something with a for loop lets you generate more and more HTML. 1490 01:13:35,310 --> 01:13:37,230 And this is like every website out there. 1491 01:13:37,230 --> 01:13:38,100 For instance, Gmail. 1492 01:13:38,100 --> 01:13:42,090 When you visit your inbox and you see all of this big table of emails, 1493 01:13:42,090 --> 01:13:44,730 Google has not hardcoded your emails manually. 1494 01:13:44,730 --> 01:13:46,560 They have grabbed them from a database. 1495 01:13:46,560 --> 01:13:48,310 They have some kind of for loop like this, 1496 01:13:48,310 --> 01:13:54,295 and are just outputting table row after table row or div after div dynamically. 1497 01:13:54,295 --> 01:13:56,670 All right, so now, let's go ahead and change this, maybe, 1498 01:13:56,670 --> 01:14:02,470 to, oh, how about little checkboxes or radio buttons. 1499 01:14:02,470 --> 01:14:03,810 So let me go ahead and do this. 1500 01:14:03,810 --> 01:14:08,670 Instead of a select menu, I'm going to go ahead and do something like this. 1501 01:14:08,670 --> 01:14:14,590 For each of these sports let me go ahead and output, not an option, 1502 01:14:14,590 --> 01:14:17,520 but let me go ahead and output an input tag, 1503 01:14:17,520 --> 01:14:21,540 the name for which is quote unquote "sport," the type of which 1504 01:14:21,540 --> 01:14:27,240 is checkbox, the value of which is going to be the current "sport," 1505 01:14:27,240 --> 01:14:31,642 quote unquote, and then afterward I need to redundantly, seemingly, 1506 01:14:31,642 --> 01:14:32,350 output the sport. 1507 01:14:32,350 --> 01:14:34,150 So you see a word next to the checkbox. 1508 01:14:34,150 --> 01:14:36,400 And we'll look at the result of this in just a moment. 1509 01:14:36,400 --> 01:14:39,960 So it's actually a little simpler than a select menu, a dropdown menu, 1510 01:14:39,960 --> 01:14:43,200 because now watch what happens if I reload my form. 1511 01:14:43,200 --> 01:14:46,560 Different user interface, and it's not as pretty, 1512 01:14:46,560 --> 01:14:49,840 but it's going to allow users to sign up for multiple sports at once now, 1513 01:14:49,840 --> 01:14:50,590 it would seem. 1514 01:14:50,590 --> 01:14:53,920 Now I can click on basketball and football and soccer 1515 01:14:53,920 --> 01:14:56,260 or some other combination thereof. 1516 01:14:56,260 --> 01:15:00,040 If I view the page's source, this is, again, the power of templating. 1517 01:15:00,040 --> 01:15:04,220 I didn't have to type out four inputs, I got them now automatically. 1518 01:15:04,220 --> 01:15:07,540 And these things all have the same name, but that's OK. 1519 01:15:07,540 --> 01:15:11,170 It turns out with Flask, if it sees multiple values for the same name, 1520 01:15:11,170 --> 01:15:15,160 it's going to hand them back to you as a list if you use the right function. 1521 01:15:15,160 --> 01:15:18,430 All right, but suppose we don't want users registering for multiple sports. 1522 01:15:18,430 --> 01:15:19,810 Maybe capacity is an issue. 1523 01:15:19,810 --> 01:15:23,440 Let me go ahead and change this checkbox to radio button, which 1524 01:15:23,440 --> 01:15:25,400 a radio button is mutually exclusive. 1525 01:15:25,400 --> 01:15:27,130 So you can only sign up for one. 1526 01:15:27,130 --> 01:15:31,780 So now, once I reload the page, there we go. 1527 01:15:31,780 --> 01:15:34,240 It now looks like this. 1528 01:15:34,240 --> 01:15:39,010 And because I've given each of these inputs the same name, quote unquote, 1529 01:15:39,010 --> 01:15:42,410 "sport," that's what makes them mutually exclusive. 1530 01:15:42,410 --> 01:15:45,730 The browser knows all four of these things are types of sports, 1531 01:15:45,730 --> 01:15:48,970 therefore I'm only going to let you select one of these things. 1532 01:15:48,970 --> 01:15:51,310 And that's simply because they all have the same name. 1533 01:15:51,310 --> 01:15:54,730 Again, if I view page source, notice all of them, name equal sport, 1534 01:15:54,730 --> 01:15:58,780 name equals sport, name equals sport, but what differs is the value 1535 01:15:58,780 --> 01:16:01,942 that each one is going to have. 1536 01:16:01,942 --> 01:16:07,490 All right, any questions, then, on this approach? 1537 01:16:07,490 --> 01:16:07,990 All right. 1538 01:16:07,990 --> 01:16:09,990 Well, let me go ahead and open a version of this 1539 01:16:09,990 --> 01:16:13,690 that I made in advance that's going to now start saving the information. 1540 01:16:13,690 --> 01:16:15,580 So thus far, we're not quite at the point 1541 01:16:15,580 --> 01:16:18,910 of where this website was, which actually allowed the proctors to see, 1542 01:16:18,910 --> 01:16:21,430 like in a database, everyone who had registered for sports. 1543 01:16:21,430 --> 01:16:24,130 Now, we're literally telling students you are registered 1544 01:16:24,130 --> 01:16:26,050 or you are not registered, but we're literally 1545 01:16:26,050 --> 01:16:28,130 doing nothing with this information. 1546 01:16:28,130 --> 01:16:30,770 So how might we go about implementing this? 1547 01:16:30,770 --> 01:16:32,740 Well, let me go ahead and close these tabs, 1548 01:16:32,740 --> 01:16:38,140 and let me go into what I call version three of this in the code for today. 1549 01:16:38,140 --> 01:16:41,950 And let me go into my source nine directory, FroshIMS3, 1550 01:16:41,950 --> 01:16:44,890 and let me go ahead and open up app.py. 1551 01:16:44,890 --> 01:16:46,450 So this is a premade version. 1552 01:16:46,450 --> 01:16:48,380 I've gotten rid of football, in this case. 1553 01:16:48,380 --> 01:16:51,100 But I've added one thing at the very top. 1554 01:16:51,100 --> 01:16:56,110 What's, in English, does this represent on line seven? 1555 01:16:56,110 --> 01:16:58,150 What would you describe what that thing is? 1556 01:16:58,150 --> 01:17:01,230 1557 01:17:01,230 --> 01:17:02,700 What are we looking at? 1558 01:17:02,700 --> 01:17:03,690 What do you think? 1559 01:17:03,690 --> 01:17:04,410 AUDIENCE: It's an empty dictionary. 1560 01:17:04,410 --> 01:17:05,610 DAVID: Yeah, it's an empty dictionary, right? 1561 01:17:05,610 --> 01:17:07,860 Registrants is apparently a variable on the left. 1562 01:17:07,860 --> 01:17:10,168 It's being assigned an empty dictionary on the right. 1563 01:17:10,168 --> 01:17:12,210 And a dictionary, again, is just key value pairs. 1564 01:17:12,210 --> 01:17:15,690 Here, again, is where dictionaries are just such a useful data structure. 1565 01:17:15,690 --> 01:17:16,198 Why? 1566 01:17:16,198 --> 01:17:18,990 Because this is going to allow me to remember that David registered 1567 01:17:18,990 --> 01:17:21,510 for ultimate frisbee, Carter registered for soccer, 1568 01:17:21,510 --> 01:17:23,070 Emma registered for something else. 1569 01:17:23,070 --> 01:17:26,550 You can associate keys with values, names with sports, 1570 01:17:26,550 --> 01:17:29,770 assuming a model where you can only register for one sport for now. 1571 01:17:29,770 --> 01:17:35,040 And so let's see what the logic is that handles this. 1572 01:17:35,040 --> 01:17:38,520 Here in my register route in the code I've premade, 1573 01:17:38,520 --> 01:17:40,440 notice that I'm validating the user's name. 1574 01:17:40,440 --> 01:17:42,630 Slightly differently from before but same idea. 1575 01:17:42,630 --> 01:17:45,720 I'm using request.form.get to get the human's name. 1576 01:17:45,720 --> 01:17:48,750 If not name, so if the human did not type a name, 1577 01:17:48,750 --> 01:17:51,480 I'm going to output error.html. 1578 01:17:51,480 --> 01:17:55,890 But notice I've started to make the user interface more expressive. 1579 01:17:55,890 --> 01:17:59,790 I'm telling the user, apparently, with a message what they did wrong. 1580 01:17:59,790 --> 01:18:00,870 Well how? 1581 01:18:00,870 --> 01:18:03,420 I'm apparently passing to my error template, 1582 01:18:03,420 --> 01:18:06,773 instead of just failure.html, a specific message. 1583 01:18:06,773 --> 01:18:08,190 So let's go down this rabbit hole. 1584 01:18:08,190 --> 01:18:14,290 Let me actually go into templates/error.hml, and sure enough, 1585 01:18:14,290 --> 01:18:18,000 here's a new file I created here, that adorably is apparently going to have 1586 01:18:18,000 --> 01:18:21,570 a grumpy cat as part of the error message, but notice what I've done. 1587 01:18:21,570 --> 01:18:26,820 In my block body I've got an H1 tag that just says error, big and bold. 1588 01:18:26,820 --> 01:18:29,370 I then have a paragraph tag that plugs in whatever 1589 01:18:29,370 --> 01:18:33,120 the error message is that the controller, app.py, is passing in. 1590 01:18:33,120 --> 01:18:36,450 And then just for fun, I have a picture of a grumpy cat connoting 1591 01:18:36,450 --> 01:18:37,990 that there was, in fact, an error. 1592 01:18:37,990 --> 01:18:39,000 Let's keep looking. 1593 01:18:39,000 --> 01:18:40,660 How do I validate sport? 1594 01:18:40,660 --> 01:18:45,030 I do similarly request.form.get of sport, 1595 01:18:45,030 --> 01:18:46,800 and I store it in a variable called sport. 1596 01:18:46,800 --> 01:18:50,590 If there's no such sport, that is the human did not check any of the boxes, 1597 01:18:50,590 --> 01:18:53,010 then I'm going to render error.html two, but I'm 1598 01:18:53,010 --> 01:18:55,600 going to give a different message, missing sport. 1599 01:18:55,600 --> 01:19:00,690 Else, if the sport they did type in is not in my sports global variable, 1600 01:19:00,690 --> 01:19:04,230 I'm going to render error.html, but complain differently, 1601 01:19:04,230 --> 01:19:07,020 you gave me an invalid sport somehow. 1602 01:19:07,020 --> 01:19:09,270 As if a hacker went into the HTML of the page, 1603 01:19:09,270 --> 01:19:11,617 changed it to add their own sport like volleyball. 1604 01:19:11,617 --> 01:19:13,950 Even though it's not offered, they submitted volleyball. 1605 01:19:13,950 --> 01:19:17,400 But that's OK, I'm rejecting it, even though they might have maliciously 1606 01:19:17,400 --> 01:19:20,910 tried to send it to me by changing the dom locally. 1607 01:19:20,910 --> 01:19:23,070 And then really, the magic is just this. 1608 01:19:23,070 --> 01:19:25,680 I remember that this person has registered 1609 01:19:25,680 --> 01:19:28,860 by indexing into the registrant dictionary 1610 01:19:28,860 --> 01:19:33,870 using the name the human typed in as the key and assigning it a value of sport. 1611 01:19:33,870 --> 01:19:35,140 Why is this useful? 1612 01:19:35,140 --> 01:19:37,470 Well, I added one final route here. 1613 01:19:37,470 --> 01:19:41,910 I have a /registrants route with a registrants function that renders 1614 01:19:41,910 --> 01:19:43,860 a template called registrants.html. 1615 01:19:43,860 --> 01:19:48,820 But it takes as input that global variable just like before. 1616 01:19:48,820 --> 01:19:55,200 So let's go down this rabbit hole let me go into templates registrants dot HTML. 1617 01:19:55,200 --> 01:19:56,640 Here's this template. 1618 01:19:56,640 --> 01:20:00,420 It looks a little crazy big, but it extends the layout. 1619 01:20:00,420 --> 01:20:01,620 Here comes the body. 1620 01:20:01,620 --> 01:20:04,560 I've got an H1 tag that says registrants, big and bold. 1621 01:20:04,560 --> 01:20:06,930 Then I've got a table that we saw last week. 1622 01:20:06,930 --> 01:20:10,800 This has a table head that just says name sport for two columns. 1623 01:20:10,800 --> 01:20:16,200 Then it has a table body where in, using this for loop in Jinja syntax, 1624 01:20:16,200 --> 01:20:19,410 I'm saying, for each name in the registrants variable, 1625 01:20:19,410 --> 01:20:23,400 output a table row, start tag, and end tag, inside of which, 1626 01:20:23,400 --> 01:20:26,580 two table datas, two cells, table data for name, 1627 01:20:26,580 --> 01:20:30,790 table data for registrants bracket name. 1628 01:20:30,790 --> 01:20:33,210 So it's very similar to Python syntax. 1629 01:20:33,210 --> 01:20:37,100 It essentially is Python syntax, albeit with these curly braces and the percent 1630 01:20:37,100 --> 01:20:37,600 sign. 1631 01:20:37,600 --> 01:20:39,750 So the net effect here is what? 1632 01:20:39,750 --> 01:20:43,050 Let me open up my terminal window, run Flask run. 1633 01:20:43,050 --> 01:20:47,110 Let me now go into the form that I premade here. 1634 01:20:47,110 --> 01:20:48,270 So gone is football. 1635 01:20:48,270 --> 01:20:50,190 Let me go ahead and type in David. 1636 01:20:50,190 --> 01:20:52,560 Let me choose, oh, no sport. 1637 01:20:52,560 --> 01:20:53,880 Register. 1638 01:20:53,880 --> 01:20:55,470 Error, missing sport. 1639 01:20:55,470 --> 01:20:57,120 And there is the grumpy cat. 1640 01:20:57,120 --> 01:21:00,120 So missing sport, though, specifically was outputed. 1641 01:21:00,120 --> 01:21:00,910 All right, fine. 1642 01:21:00,910 --> 01:21:03,660 Let me go ahead and say no name. 1643 01:21:03,660 --> 01:21:04,920 But I'll choose basketball. 1644 01:21:04,920 --> 01:21:06,210 Register. 1645 01:21:06,210 --> 01:21:06,990 Missing name. 1646 01:21:06,990 --> 01:21:09,480 All right, and let me maliciously, now, do this. 1647 01:21:09,480 --> 01:21:10,530 Now I'm hacking. 1648 01:21:10,530 --> 01:21:11,820 Let me go into this. 1649 01:21:11,820 --> 01:21:15,930 I'll type my name, sure, but let me go into the body tag down here. 1650 01:21:15,930 --> 01:21:20,130 Let me maliciously go down in ultimate frisbee, heck with that, let's 1651 01:21:20,130 --> 01:21:21,780 volleyball. 1652 01:21:21,780 --> 01:21:26,580 Change that and change this to volleyball. 1653 01:21:26,580 --> 01:21:27,360 Enter. 1654 01:21:27,360 --> 01:21:31,230 So now, I can register for any sport I want to create. 1655 01:21:31,230 --> 01:21:34,200 Let me click register, but invalid sports. 1656 01:21:34,200 --> 01:21:36,420 So again, that speaks to the power and the need 1657 01:21:36,420 --> 01:21:39,600 for checking things on backend and not trusting users. 1658 01:21:39,600 --> 01:21:43,830 It is that easy to hack websites otherwise if you're not validating data 1659 01:21:43,830 --> 01:21:44,530 server side. 1660 01:21:44,530 --> 01:21:46,530 All right, finally, let's just do this for real. 1661 01:21:46,530 --> 01:21:48,530 David is going to register for ultimate frisbee. 1662 01:21:48,530 --> 01:21:49,530 Clicking register. 1663 01:21:49,530 --> 01:21:52,800 And now, the output is not very pretty, but notice 1664 01:21:52,800 --> 01:21:54,790 I'm at the registrants route. 1665 01:21:54,790 --> 01:21:56,880 And if I zoom out, I have an HTML table. 1666 01:21:56,880 --> 01:22:00,370 Two columns, name and sport, David and ultimate frisbee. 1667 01:22:00,370 --> 01:22:04,120 Let me go back to the form, letting me pretend Carter walked up to my laptop 1668 01:22:04,120 --> 01:22:05,560 and registered for basketball. 1669 01:22:05,560 --> 01:22:06,460 Register. 1670 01:22:06,460 --> 01:22:11,350 Now we see two rows in this table, David, ultimate frisbee, Carter, 1671 01:22:11,350 --> 01:22:11,860 basketball. 1672 01:22:11,860 --> 01:22:13,652 And if we do this one more time, maybe Emma 1673 01:22:13,652 --> 01:22:16,000 comes along and registers for soccer register. 1674 01:22:16,000 --> 01:22:20,905 All of this information is being stored in this dictionary, now. 1675 01:22:20,905 --> 01:22:22,030 All right, so that's great. 1676 01:22:22,030 --> 01:22:26,230 Now we have a database, albeit in the form of a Python dictionary. 1677 01:22:26,230 --> 01:22:31,277 But why is this, maybe, not the best implementation? 1678 01:22:31,277 --> 01:22:32,110 Why is it not great? 1679 01:22:32,110 --> 01:22:32,954 Yeah. 1680 01:22:32,954 --> 01:22:35,858 AUDIENCE: You are storing [INAUDIBLE]. 1681 01:22:35,858 --> 01:22:40,590 1682 01:22:40,590 --> 01:22:41,090 DAVID: Yeah. 1683 01:22:41,090 --> 01:22:43,715 So we're only storing this dictionary in the computer's memory, 1684 01:22:43,715 --> 01:22:46,970 and that's great until I hit Control C and kill Flask, 1685 01:22:46,970 --> 01:22:48,410 stopping the web server. 1686 01:22:48,410 --> 01:22:51,650 Or the server reboots, or maybe I close my laptop or whatever. 1687 01:22:51,650 --> 01:22:54,950 If the server stops running, memory is going to be lost. 1688 01:22:54,950 --> 01:22:56,420 RAM is volatile. 1689 01:22:56,420 --> 01:22:59,550 It's thrown away when you lose power or stop the program. 1690 01:22:59,550 --> 01:23:01,340 So maybe this isn't the best approach. 1691 01:23:01,340 --> 01:23:03,600 Maybe it would be better to use a CSV file. 1692 01:23:03,600 --> 01:23:06,230 And in fact, some 20 years ago, that's literally what I did. 1693 01:23:06,230 --> 01:23:08,130 I stored everything in a CSV file. 1694 01:23:08,130 --> 01:23:10,640 But let's skip that step, because we already saw last week, 1695 01:23:10,640 --> 01:23:13,790 or a couple of weeks ago now, how we can use SQLite. 1696 01:23:13,790 --> 01:23:16,370 Let's see if we can't marry in some SQL here 1697 01:23:16,370 --> 01:23:20,370 to store an actual database for the program. 1698 01:23:20,370 --> 01:23:22,310 Let me go back here and let me open up, say, 1699 01:23:22,310 --> 01:23:25,850 version four of this, which is almost the same but it 1700 01:23:25,850 --> 01:23:27,530 adds a bit more functionality. 1701 01:23:27,530 --> 01:23:32,780 Let me close these tabs and let me open up app.py now in version four. 1702 01:23:32,780 --> 01:23:35,990 So notice it's almost the same, but at the top, 1703 01:23:35,990 --> 01:23:40,490 I'm creating a database connection to a database called FroshIMS.db. 1704 01:23:40,490 --> 01:23:42,283 So that's a database I created in advance. 1705 01:23:42,283 --> 01:23:43,700 So let's go down that rabbit hole. 1706 01:23:43,700 --> 01:23:44,720 What does it look like? 1707 01:23:44,720 --> 01:23:46,860 Let me make my terminal window bigger. 1708 01:23:46,860 --> 01:23:50,600 Let me run SQLite 3 of FroshIMS.db. 1709 01:23:50,600 --> 01:23:51,290 OK, I'm in. 1710 01:23:51,290 --> 01:23:52,580 Let's do .schema. 1711 01:23:52,580 --> 01:23:55,670 and let's just infer what I designed this to be. 1712 01:23:55,670 --> 01:23:59,960 I have a table called registrants, which has one, two, three columns. 1713 01:23:59,960 --> 01:24:04,340 An ID column that's an integer, a name column that's text but cannot be null, 1714 01:24:04,340 --> 01:24:06,950 and a sport column that's also text, cannot be null, 1715 01:24:06,950 --> 01:24:08,600 and the primary key is just ID. 1716 01:24:08,600 --> 01:24:11,630 So that I have a unique ID for every registration. 1717 01:24:11,630 --> 01:24:14,150 Let's see if there's anyone in there yet. 1718 01:24:14,150 --> 01:24:17,843 Select star from registrants. 1719 01:24:17,843 --> 01:24:19,010 OK, there's no one in there. 1720 01:24:19,010 --> 01:24:20,600 No one is yet registered for sports. 1721 01:24:20,600 --> 01:24:23,180 So let's go back to the code and continue on. 1722 01:24:23,180 --> 01:24:26,030 In my code now, I've got the same global variable 1723 01:24:26,030 --> 01:24:29,270 for validation and generation of my HTML. 1724 01:24:29,270 --> 01:24:31,760 Looks like my index route is the same. 1725 01:24:31,760 --> 01:24:35,480 It's dynamically generating the menu of sports. 1726 01:24:35,480 --> 01:24:37,137 Interestingly, we'll come back to this. 1727 01:24:37,137 --> 01:24:39,470 There's a deregister route that's going to allow someone 1728 01:24:39,470 --> 01:24:44,330 to deregister themselves if they want to exit the sport 1729 01:24:44,330 --> 01:24:45,530 or undo their registration. 1730 01:24:45,530 --> 01:24:46,940 But this is the juicy part. 1731 01:24:46,940 --> 01:24:49,580 Here's my new and improved register route. 1732 01:24:49,580 --> 01:24:52,940 Still works on POST, so some mild privacy there. 1733 01:24:52,940 --> 01:24:55,770 I'm validating the submission as follows. 1734 01:24:55,770 --> 01:24:59,180 I'm getting the user's inputted name, the user's inputted sport, 1735 01:24:59,180 --> 01:25:03,380 and if it is not a name or the sport is not in sports, 1736 01:25:03,380 --> 01:25:05,197 I'm going to render failure.html. 1737 01:25:05,197 --> 01:25:06,030 So I kept it simple. 1738 01:25:06,030 --> 01:25:07,380 There's no cat in this version. 1739 01:25:07,380 --> 01:25:08,780 It just says failure. 1740 01:25:08,780 --> 01:25:12,500 Otherwise, recall how we co-mingled SQL and Python before. 1741 01:25:12,500 --> 01:25:15,800 We're using CS50's SQL library, but that just 1742 01:25:15,800 --> 01:25:19,130 makes it a little easier to execute SQL queries and we're executing this. 1743 01:25:19,130 --> 01:25:22,760 Insert into registrants name comma sport. 1744 01:25:22,760 --> 01:25:27,390 What two values, the name and the sport, that came from that HTML form. 1745 01:25:27,390 --> 01:25:30,260 And then lastly, and this is a new function that we're calling out 1746 01:25:30,260 --> 01:25:33,020 explicitly now, Flask also gives you access 1747 01:25:33,020 --> 01:25:39,645 to a redirect function, which is how safetyschool.org, Harvardsucks.org, 1748 01:25:39,645 --> 01:25:42,020 and all these other sites we played around with last week 1749 01:25:42,020 --> 01:25:45,500 we're all implemented redirecting the user from one place to another. 1750 01:25:45,500 --> 01:25:48,980 This Flask function redirect comes from my just 1751 01:25:48,980 --> 01:25:52,460 having imported it at the very top of this file. 1752 01:25:52,460 --> 01:25:57,380 It handles the HTTP 301 or 302 or 307 code, whatever the appropriate one is. 1753 01:25:57,380 --> 01:25:59,450 It does that for me. 1754 01:25:59,450 --> 01:26:04,520 All right, so that's it for registering via this route. 1755 01:26:04,520 --> 01:26:08,150 Let's look at what the registrant's route is. 1756 01:26:08,150 --> 01:26:11,270 Here, we have a new route for /registrants. 1757 01:26:11,270 --> 01:26:14,280 And instead of just iterating over a dictionary like before, 1758 01:26:14,280 --> 01:26:18,710 we're getting back, let's see, db.execute of select star 1759 01:26:18,710 --> 01:26:19,550 from registrants. 1760 01:26:19,550 --> 01:26:22,640 So that's literally the programmatic version of what I just did manually. 1761 01:26:22,640 --> 01:26:24,650 That gives me back a list of dictionaries, 1762 01:26:24,650 --> 01:26:27,890 each of which represents one row in the table. 1763 01:26:27,890 --> 01:26:31,070 Then, I'm going to render register and start HTML, 1764 01:26:31,070 --> 01:26:34,520 passing in literally that list of dictionaries 1765 01:26:34,520 --> 01:26:37,800 just like using CS50's library in the past. 1766 01:26:37,800 --> 01:26:40,760 So let's go and look at these-- that form. 1767 01:26:40,760 --> 01:26:46,610 If I go into templates and open up registrants.html, 1768 01:26:46,610 --> 01:26:49,610 oh, OK, it's just a table like before. 1769 01:26:49,610 --> 01:26:52,910 And actually, let me change this syntactically for consistency. 1770 01:26:52,910 --> 01:26:58,550 We have a Jinja for loop that iterates over each registrant 1771 01:26:58,550 --> 01:27:01,910 and for each of them, outputs a table row. 1772 01:27:01,910 --> 01:27:03,140 Oh, but this is interesting. 1773 01:27:03,140 --> 01:27:06,860 Instead of just having two columns with the person's name and sport, 1774 01:27:06,860 --> 01:27:09,892 notice that I'm also outputting a full-fledged form. 1775 01:27:09,892 --> 01:27:11,600 All right, this is starting to get juicy. 1776 01:27:11,600 --> 01:27:14,900 So let's actually go back to my terminal window, 1777 01:27:14,900 --> 01:27:18,770 run Flask, and actually see what this example looks like now. 1778 01:27:18,770 --> 01:27:20,550 Let me reload the page. 1779 01:27:20,550 --> 01:27:21,050 All right. 1780 01:27:21,050 --> 01:27:22,830 In the home page, it looks exactly the same. 1781 01:27:22,830 --> 01:27:24,413 But let me now register for something. 1782 01:27:24,413 --> 01:27:27,030 David for ultimate frisbee, register. 1783 01:27:27,030 --> 01:27:27,680 Oh, damn it. 1784 01:27:27,680 --> 01:27:30,195 1785 01:27:30,195 --> 01:27:31,070 Let's try this again. 1786 01:27:31,070 --> 01:27:34,800 David registering for ultimate frisbee, register. 1787 01:27:34,800 --> 01:27:35,300 OK. 1788 01:27:35,300 --> 01:27:37,370 So good thing I have deregister. 1789 01:27:37,370 --> 01:27:39,170 So this is what it should now look like. 1790 01:27:39,170 --> 01:27:44,358 I have a page at the route called /registrants that has a table with two 1791 01:27:44,358 --> 01:27:46,400 columns, name and sport, David, ultimate frisbee. 1792 01:27:46,400 --> 01:27:47,760 But oh, wait, a third column. 1793 01:27:47,760 --> 01:27:48,260 Why? 1794 01:27:48,260 --> 01:27:52,700 Because if I view the page source, notice that it's not the prettiest UI. 1795 01:27:52,700 --> 01:27:56,810 For every row in this table, I'm also going to be outputting a form just 1796 01:27:56,810 --> 01:27:58,770 to deregister that user. 1797 01:27:58,770 --> 01:28:02,330 But before we see how that works, let me go ahead and register Carter, 1798 01:28:02,330 --> 01:28:02,920 for instance. 1799 01:28:02,920 --> 01:28:04,520 So Carter will give you basketball. 1800 01:28:04,520 --> 01:28:05,780 Again, register. 1801 01:28:05,780 --> 01:28:07,200 The table grows. 1802 01:28:07,200 --> 01:28:10,310 Now, let me go back and let's register Emma for soccer. 1803 01:28:10,310 --> 01:28:12,290 And the table should grow. 1804 01:28:12,290 --> 01:28:17,720 Before we look at that HTML, let's go back to my terminal window. 1805 01:28:17,720 --> 01:28:21,980 Let's go into SQLite FroshIMS. 1806 01:28:21,980 --> 01:28:32,390 Let me go into FroshIMS, and let me open up with SQLite 3 FroshIMS.db. 1807 01:28:32,390 --> 01:28:34,700 And now do select star from registrants. 1808 01:28:34,700 --> 01:28:38,630 And whereas, previously, when I executed this there were zero people, now 1809 01:28:38,630 --> 01:28:39,710 there's indeed three. 1810 01:28:39,710 --> 01:28:43,350 So now we see exactly what's going on underneath the hood. 1811 01:28:43,350 --> 01:28:46,700 So let's look at this form now-- this page now. 1812 01:28:46,700 --> 01:28:51,380 If I want to unregister, deregister one of these people specifically, 1813 01:28:51,380 --> 01:28:53,180 how do we do this? 1814 01:28:53,180 --> 01:28:55,280 Clicking one of those buttons will indeed 1815 01:28:55,280 --> 01:28:58,260 delete the row from the database. 1816 01:28:58,260 --> 01:29:03,650 But how do we go about linking a web page with Python code with a database? 1817 01:29:03,650 --> 01:29:05,690 This is the last piece of the puzzle. 1818 01:29:05,690 --> 01:29:09,470 Up until now, everything's been with forms and also with URLs. 1819 01:29:09,470 --> 01:29:11,600 But what if the user is not typing anything in, 1820 01:29:11,600 --> 01:29:13,790 they're just clicking a button? 1821 01:29:13,790 --> 01:29:15,660 Well, watch this. 1822 01:29:15,660 --> 01:29:18,135 Let me go ahead and sniff the traffic, which 1823 01:29:18,135 --> 01:29:19,760 you could be in the habit of doing now. 1824 01:29:19,760 --> 01:29:23,570 Any time you're curious how a website works, let me go to the Network tab. 1825 01:29:23,570 --> 01:29:28,010 And Carter, shall we deregister you from basketball? 1826 01:29:28,010 --> 01:29:31,550 Let's deregister Carter and let's see what just happened. 1827 01:29:31,550 --> 01:29:35,630 If I look at the deregister request, notice that it's a POST. 1828 01:29:35,630 --> 01:29:38,450 The status code that eventually came back as 302, 1829 01:29:38,450 --> 01:29:40,880 but let's look at the request itself. 1830 01:29:40,880 --> 01:29:43,610 All the headers there we'll ignore. 1831 01:29:43,610 --> 01:29:48,110 The only thing that button submits, cleverly, 1832 01:29:48,110 --> 01:29:52,130 is an ID parameter, a key equaling two. 1833 01:29:52,130 --> 01:29:56,390 What does two presumably represent or map to? 1834 01:29:56,390 --> 01:29:59,300 Where did this two come from? 1835 01:29:59,300 --> 01:30:03,020 It doesn't say Carter, it doesn't say basketball? 1836 01:30:03,020 --> 01:30:03,568 What is it? 1837 01:30:03,568 --> 01:30:05,360 AUDIENCE: The second person who registered. 1838 01:30:05,360 --> 01:30:06,770 DAVID: The second person that registered. 1839 01:30:06,770 --> 01:30:09,920 So those primary keys that we started talking about a couple of weeks 1840 01:30:09,920 --> 01:30:13,220 ago, why it's useful to be able to uniquely identify a row in a table, 1841 01:30:13,220 --> 01:30:15,470 here is just one of the reasons why. 1842 01:30:15,470 --> 01:30:20,510 If it suffices for me just to send the ID number of the person 1843 01:30:20,510 --> 01:30:25,380 I want to delete from the database, because I can then have code like this. 1844 01:30:25,380 --> 01:30:31,560 If I go into app.py and I look at my deregister route now, the last of them, 1845 01:30:31,560 --> 01:30:33,410 notice that I got this. 1846 01:30:33,410 --> 01:30:37,880 I first go into the form, and I get the ID that was submitted, hopefully. 1847 01:30:37,880 --> 01:30:42,110 If there was, in fact, an ID, and the form wasn't somehow empty, 1848 01:30:42,110 --> 01:30:43,880 I execute this line of code. 1849 01:30:43,880 --> 01:30:46,880 Delete from registrants where ID equals question mark, 1850 01:30:46,880 --> 01:30:51,440 and then I plug-in that number, deleting Carter and only Carter. 1851 01:30:51,440 --> 01:30:54,710 And I'm not using his name, because what if we have two people named Carter, 1852 01:30:54,710 --> 01:30:56,240 two people named Emma or David? 1853 01:30:56,240 --> 01:30:57,840 You don't want to delete both of them. 1854 01:30:57,840 --> 01:31:01,970 That's why these unique IDs are so, so important. 1855 01:31:01,970 --> 01:31:03,860 And here's another reason why. 1856 01:31:03,860 --> 01:31:07,250 You don't want to store some things in URLs. 1857 01:31:07,250 --> 01:31:11,990 Suppose we went to this URL, deregister?ID=3. 1858 01:31:11,990 --> 01:31:15,500 1859 01:31:15,500 --> 01:31:20,370 Suppose I, maliciously, emailed this URL to Emma. 1860 01:31:20,370 --> 01:31:22,370 It doesn't matter so much what the beginning is, 1861 01:31:22,370 --> 01:31:28,490 but supposed I emailed her this URL, /deregister?ID=3, and I said, hey, 1862 01:31:28,490 --> 01:31:29,930 Emma, click this. 1863 01:31:29,930 --> 01:31:32,570 And it uses GET instead of POST. 1864 01:31:32,570 --> 01:31:34,565 What did I just trick her into doing? 1865 01:31:34,565 --> 01:31:37,608 1866 01:31:37,608 --> 01:31:39,400 What's going to happen if Emma clicks this? 1867 01:31:39,400 --> 01:31:39,900 Yeah? 1868 01:31:39,900 --> 01:31:41,260 AUDIENCE: Deregistering? 1869 01:31:41,260 --> 01:31:43,760 DAVID: You would trick her into deregistering herself. 1870 01:31:43,760 --> 01:31:44,260 Why? 1871 01:31:44,260 --> 01:31:47,050 Because if she's logged into this FroshIMS website, 1872 01:31:47,050 --> 01:31:51,100 and the URL contains her ID just because I'm being malicious, 1873 01:31:51,100 --> 01:31:54,160 and she clicked on it and the website is using GET, 1874 01:31:54,160 --> 01:31:56,950 unfortunately, GET URLs are, again, stateful. 1875 01:31:56,950 --> 01:31:59,020 They have state information in the URLs. 1876 01:31:59,020 --> 01:32:01,770 And in this case, it's enough to delete the user and boom, 1877 01:32:01,770 --> 01:32:04,382 she would have accidentally deregistered herself. 1878 01:32:04,382 --> 01:32:05,590 And this is pretty innocuous. 1879 01:32:05,590 --> 01:32:08,110 Suppose that this was her bank account trying 1880 01:32:08,110 --> 01:32:09,910 to make a withdrawal or a deposit. 1881 01:32:09,910 --> 01:32:13,060 Suppose that this were some other website, a Facebook URL, 1882 01:32:13,060 --> 01:32:15,577 trying to trick her into posting something automatically. 1883 01:32:15,577 --> 01:32:17,410 Here, too, is another consideration when you 1884 01:32:17,410 --> 01:32:21,640 should use POST versus GET, because GET requests can 1885 01:32:21,640 --> 01:32:26,570 be plugged into emails sent via Slack messages, text messages, or the like. 1886 01:32:26,570 --> 01:32:28,840 And unless there's a prompt saying, are you sure 1887 01:32:28,840 --> 01:32:31,990 you want to deregister yourself, you might blindly 1888 01:32:31,990 --> 01:32:34,090 trick the user into being vulnerable to what's 1889 01:32:34,090 --> 01:32:36,460 called a cross-site request forgery. 1890 01:32:36,460 --> 01:32:39,640 A fancy way of saying you trick them into clicking a link 1891 01:32:39,640 --> 01:32:43,480 that they shouldn't have, because the website was using GET alone. 1892 01:32:43,480 --> 01:32:47,350 All right, any question, then, on these building blocks? 1893 01:32:47,350 --> 01:32:49,168 Yeah. 1894 01:32:49,168 --> 01:32:54,514 AUDIENCE: What do the first thing in the instance of the SQL 1895 01:32:54,514 --> 01:32:56,470 [INAUDIBLE] where they have three slashes? 1896 01:32:56,470 --> 01:32:57,740 What does that mean? 1897 01:32:57,740 --> 01:32:59,695 DAVID: When three columns, you mean? 1898 01:32:59,695 --> 01:33:04,550 AUDIENCE: No, three forward slashes. 1899 01:33:04,550 --> 01:33:07,120 DAVID: The three forward slashes. 1900 01:33:07,120 --> 01:33:08,645 I'm not sure I follow. 1901 01:33:08,645 --> 01:33:11,615 AUDIENCE: Yeah, so I think it's in [INAUDIBLE].. 1902 01:33:11,615 --> 01:33:15,090 1903 01:33:15,090 --> 01:33:18,270 DAVID: Sorry, it's in where? 1904 01:33:18,270 --> 01:33:19,473 Which file? 1905 01:33:19,473 --> 01:33:24,303 AUDIENCE: It's in [INAUDIBLE] scroll up. 1906 01:33:24,303 --> 01:33:25,269 [INAUDIBLE] 1907 01:33:25,269 --> 01:33:28,543 1908 01:33:28,543 --> 01:33:29,960 DAVID: Sorry, the other direction? 1909 01:33:29,960 --> 01:33:30,780 AUDIENCE: Yeah. 1910 01:33:30,780 --> 01:33:32,216 DAVID: OK. 1911 01:33:32,216 --> 01:33:35,084 AUDIENCE: [INAUDIBLE]. 1912 01:33:35,084 --> 01:33:38,645 So please scroll a little bit more. 1913 01:33:38,645 --> 01:33:39,770 DAVID: Keep scrolling more? 1914 01:33:39,770 --> 01:33:40,790 Oh, this thing. 1915 01:33:40,790 --> 01:33:42,320 OK, sorry. 1916 01:33:42,320 --> 01:33:50,000 This is a URI, it's typical syntax that's referring to the SQLite 1917 01:33:50,000 --> 01:33:54,590 protocol, so to speak, which means use SQLite to talk to a file locally. 1918 01:33:54,590 --> 01:33:57,560 :// is just like you and I see in URLs. 1919 01:33:57,560 --> 01:34:00,200 The third slash, essentially, means current folder. 1920 01:34:00,200 --> 01:34:00,860 That's all. 1921 01:34:00,860 --> 01:34:03,700 So it's a weird curiosity, but it's typical 1922 01:34:03,700 --> 01:34:06,200 whenever you're referring to a local file and not one that's 1923 01:34:06,200 --> 01:34:07,490 elsewhere on the internet. 1924 01:34:07,490 --> 01:34:10,550 That's a bit of an oversimplification, but that's indeed a convention. 1925 01:34:10,550 --> 01:34:12,710 Sorry for not clicking earlier. 1926 01:34:12,710 --> 01:34:15,530 All right, let's do one other iteration of FroshIMS 1927 01:34:15,530 --> 01:34:18,860 here just to show what I was actually doing too, back in the day, 1928 01:34:18,860 --> 01:34:21,800 was not only storing these things in CSV files, as I recall. 1929 01:34:21,800 --> 01:34:24,285 I was also automatically generating an email 1930 01:34:24,285 --> 01:34:26,660 to the proctor in charge of the intramural sports program 1931 01:34:26,660 --> 01:34:29,750 so that they would have sort of a running history of people registering 1932 01:34:29,750 --> 01:34:31,890 and they could easily reply to them as well. 1933 01:34:31,890 --> 01:34:35,520 Let me go into FroshIMS version five, which I precreated here, 1934 01:34:35,520 --> 01:34:40,880 and let me go ahead and open up, say, app.py this time. 1935 01:34:40,880 --> 01:34:43,370 And this is some code that I wrote in advance. 1936 01:34:43,370 --> 01:34:47,160 And it looks a little scary at first glance, but I've done the following. 1937 01:34:47,160 --> 01:34:52,550 I have now added the Flask mail library to the picture 1938 01:34:52,550 --> 01:34:55,700 by adding Flask mail to requirements.txt and running a command 1939 01:34:55,700 --> 01:34:59,340 to automatically install email support for Flask as well. 1940 01:34:59,340 --> 01:35:02,090 And this is a little bit cryptic, but it's honestly mostly 1941 01:35:02,090 --> 01:35:03,860 copy paste from the documentation. 1942 01:35:03,860 --> 01:35:06,590 What I'm doing here is I'm configuring my Flask 1943 01:35:06,590 --> 01:35:09,960 application with a few configuration variables, if you will. 1944 01:35:09,960 --> 01:35:13,460 This is the syntax for that. app.config is a special dictionary that 1945 01:35:13,460 --> 01:35:17,840 comes with Flask that is automatically created when you create the app appear 1946 01:35:17,840 --> 01:35:21,200 on line nine, and I just had to fill in a whole bunch of configuration 1947 01:35:21,200 --> 01:35:23,720 values for the default sender address that I 1948 01:35:23,720 --> 01:35:27,710 want to send email as, the default password I want to use to send email, 1949 01:35:27,710 --> 01:35:30,890 the port number, the TCP port, that we talked about last week. 1950 01:35:30,890 --> 01:35:34,730 The mail server, I'm going to use Gmail's smtp.gmail.com server. 1951 01:35:34,730 --> 01:35:36,770 Use TLS, this means use encryption. 1952 01:35:36,770 --> 01:35:37,910 So I set that to true. 1953 01:35:37,910 --> 01:35:40,800 Mail username, this is going to grab it from my environment. 1954 01:35:40,800 --> 01:35:44,210 So for security purposes, I didn't want to hard code my own Gmail username 1955 01:35:44,210 --> 01:35:46,262 and password into the code. 1956 01:35:46,262 --> 01:35:49,220 So I'm actually storing those in what are called environment variables. 1957 01:35:49,220 --> 01:35:51,350 You'll see more of these in problem set nine, 1958 01:35:51,350 --> 01:35:53,360 and it's a very common convention on a server 1959 01:35:53,360 --> 01:35:59,010 in the real world to store sensitive information in the computer's memory 1960 01:35:59,010 --> 01:36:01,880 so that it can be accessed when your website is running, 1961 01:36:01,880 --> 01:36:03,440 but not in your source code. 1962 01:36:03,440 --> 01:36:06,470 It's way too easy if you put credentials, 1963 01:36:06,470 --> 01:36:09,770 sensitive stuff in your source code, to post it to GitHub 1964 01:36:09,770 --> 01:36:13,070 or to screenshot it accidentally, or for information to leak out. 1965 01:36:13,070 --> 01:36:18,200 So for today's purposes, know that the OS.environ dictionary refers to what 1966 01:36:18,200 --> 01:36:19,820 are called environment variables. 1967 01:36:19,820 --> 01:36:23,330 And this is like an out-of-band, a special way of defining key value 1968 01:36:23,330 --> 01:36:26,360 pairs in the computer's memory by running a certain command 1969 01:36:26,360 --> 01:36:28,730 but that never show up in your actual code. 1970 01:36:28,730 --> 01:36:31,370 Otherwise, there would be so many usernames and passwords 1971 01:36:31,370 --> 01:36:34,160 accidentally visible on the internet. 1972 01:36:34,160 --> 01:36:36,560 So I've installed this in advance. 1973 01:36:36,560 --> 01:36:38,390 Let me see if I can do this correctly. 1974 01:36:38,390 --> 01:36:41,820 Let me go over to another tab in just a moment. 1975 01:36:41,820 --> 01:36:45,680 And here, I have on my second screen here, John Harvards inbox. 1976 01:36:45,680 --> 01:36:48,560 It's currently empty, and I'm going to go ahead and register 1977 01:36:48,560 --> 01:36:50,780 for some sport as John Harvard here, hopefully. 1978 01:36:50,780 --> 01:36:55,070 So let me go ahead and run Flask run on this version five. 1979 01:36:55,070 --> 01:36:58,550 Let me go ahead and reload the main screen. 1980 01:36:58,550 --> 01:36:59,240 Not that one. 1981 01:36:59,240 --> 01:37:00,920 Let me reload the main screen here. 1982 01:37:00,920 --> 01:37:03,650 This time, clearly, I'm asking for name and email. 1983 01:37:03,650 --> 01:37:05,735 So name will be John Harvard. 1984 01:37:05,735 --> 01:37:08,010 jharvard@cs50.harvard.edu. 1985 01:37:08,010 --> 01:37:13,580 He'll register for, how about soccer. 1986 01:37:13,580 --> 01:37:15,140 Register. 1987 01:37:15,140 --> 01:37:19,850 And if I did this correctly, not only is John Harvard, on his screen, 1988 01:37:19,850 --> 01:37:28,940 seeing you are registered, but when he checks his email on this other screen, 1989 01:37:28,940 --> 01:37:35,240 crossing his fingers that this actually works as a demonstration, 1990 01:37:35,240 --> 01:37:37,325 and I promise it did right before class. 1991 01:37:37,325 --> 01:37:43,370 1992 01:37:43,370 --> 01:37:45,090 Horrifying. 1993 01:37:45,090 --> 01:37:47,480 I don't think there's a mistake this time. 1994 01:37:47,480 --> 01:37:50,640 1995 01:37:50,640 --> 01:37:54,060 Let me try something over here real quick, 1996 01:37:54,060 --> 01:37:57,900 but I don't think this is broken. 1997 01:37:57,900 --> 01:38:01,410 It wouldn't have said success if it were. 1998 01:38:01,410 --> 01:38:07,230 I just tried submitting again, so I just did another you are registered. 1999 01:38:07,230 --> 01:38:09,395 Oh, I'm really sad right now. 2000 01:38:09,395 --> 01:38:12,110 2001 01:38:12,110 --> 01:38:13,590 AUDIENCE: [INAUDIBLE] 2002 01:38:13,590 --> 01:38:14,547 DAVID: What's that? 2003 01:38:14,547 --> 01:38:15,920 AUDIENCE: Check spam. 2004 01:38:15,920 --> 01:38:19,760 DAVID: I could check spam, but then it's-- 2005 01:38:19,760 --> 01:38:24,230 not sure we want to show spam here on the internet that every one of us gets. 2006 01:38:24,230 --> 01:38:27,110 Oh, maybe. 2007 01:38:27,110 --> 01:38:27,900 Oh! 2008 01:38:27,900 --> 01:38:29,990 [LAUGHTER AND APPLAUDING] 2009 01:38:29,990 --> 01:38:30,740 Thank you. 2010 01:38:30,740 --> 01:38:35,300 2011 01:38:35,300 --> 01:38:35,990 OK. 2012 01:38:35,990 --> 01:38:37,760 Wow, that was a risky click I worried. 2013 01:38:37,760 --> 01:38:41,488 All right, so you are registered is the email that I sent out, 2014 01:38:41,488 --> 01:38:43,530 and it doesn't have any actual information in it. 2015 01:38:43,530 --> 01:38:45,500 But back in the day it would have, because I 2016 01:38:45,500 --> 01:38:47,330 included the student's name and their dorm 2017 01:38:47,330 --> 01:38:49,872 and all of the other fields of information that we asked for. 2018 01:38:49,872 --> 01:38:52,550 So let's just take a quick look at how that code might work. 2019 01:38:52,550 --> 01:38:55,760 I did have to configure Gmail in a certain way to allow, 2020 01:38:55,760 --> 01:38:58,430 what they call, less secure apps using SMTP, 2021 01:38:58,430 --> 01:39:00,830 which is the protocol used for outbound email. 2022 01:39:00,830 --> 01:39:05,198 But besides setting these things, let's look at the register route down here. 2023 01:39:05,198 --> 01:39:06,740 It's actually pretty straightforward. 2024 01:39:06,740 --> 01:39:09,870 In my register route, I validated the submission just like before. 2025 01:39:09,870 --> 01:39:11,100 Nothing new there. 2026 01:39:11,100 --> 01:39:15,000 I then confirmed the registration down here, nothing new there. 2027 01:39:15,000 --> 01:39:17,720 All I did was use two new lines of code. 2028 01:39:17,720 --> 01:39:20,222 And it's this easy to automate the sending of emails. 2029 01:39:20,222 --> 01:39:21,930 I apparently have done it too many times, 2030 01:39:21,930 --> 01:39:23,840 which is why it ended up in spam. 2031 01:39:23,840 --> 01:39:25,820 I created a variable called message. 2032 01:39:25,820 --> 01:39:29,220 I used a message function that I must have imported higher up, 2033 01:39:29,220 --> 01:39:30,330 so we'll go back to that. 2034 01:39:30,330 --> 01:39:33,110 Here's, apparently, the subject line as the first argument. 2035 01:39:33,110 --> 01:39:37,430 And the second argument is the named parameter recipients, 2036 01:39:37,430 --> 01:39:40,920 which takes a list of emails that should get the confirmation email. 2037 01:39:40,920 --> 01:39:43,280 So in brackets, I just put the one user's email 2038 01:39:43,280 --> 01:39:46,320 and then mail.send that message. 2039 01:39:46,320 --> 01:39:51,260 So let's scroll back up to see what message and what mail actually is. 2040 01:39:51,260 --> 01:39:52,800 Mail, I think, we saw. 2041 01:39:52,800 --> 01:39:56,030 Yep, mail is this, which I have as a variable 2042 01:39:56,030 --> 01:39:58,460 because I followed the documentation for this library. 2043 01:39:58,460 --> 01:40:04,048 You simply configure your current app with Mail support, capital M here. 2044 01:40:04,048 --> 01:40:05,840 And if you look up here now, on line seven, 2045 01:40:05,840 --> 01:40:08,990 here's the new library from Flask mail I imported. 2046 01:40:08,990 --> 01:40:13,190 Capital Mail, capital Message, so that I had the ability to create a message 2047 01:40:13,190 --> 01:40:14,690 and send a mail. 2048 01:40:14,690 --> 01:40:17,540 So such a simple thing whether you want to confirm things for users, 2049 01:40:17,540 --> 01:40:19,070 you want to do password resets. 2050 01:40:19,070 --> 01:40:22,940 It can be this easy to actually generate emails 2051 01:40:22,940 --> 01:40:25,992 provided you have the requisite access and software installed. 2052 01:40:25,992 --> 01:40:28,200 And just to make clear that I did add something here, 2053 01:40:28,200 --> 01:40:31,340 let me open up my requirements.txt file, and indeed, I 2054 01:40:31,340 --> 01:40:36,050 have both Flask and Flask-mail ready to go. 2055 01:40:36,050 --> 01:40:39,050 But I ran the command in advance to actually do that. 2056 01:40:39,050 --> 01:40:44,320 All right, any questions, then, on these examples here? 2057 01:40:44,320 --> 01:40:45,180 No? 2058 01:40:45,180 --> 01:40:45,680 All right. 2059 01:40:45,680 --> 01:40:51,810 So what other pieces might actually remain for us let me flip over here. 2060 01:40:51,810 --> 01:40:54,913 It turns out that a key component of most any web 2061 01:40:54,913 --> 01:40:57,080 application nowadays that we haven't touched on yet, 2062 01:40:57,080 --> 01:41:00,635 but it'll be one of our final flourishes today, is the notion of a session. 2063 01:41:00,635 --> 01:41:03,440 And a session is actually a feature that derives 2064 01:41:03,440 --> 01:41:06,080 from all of the basics we talked about today and last week, 2065 01:41:06,080 --> 01:41:09,590 and a session is the technical term for what you and I know as a shopping cart. 2066 01:41:09,590 --> 01:41:13,160 When you go to amazon.com and you start adding things to your shopping cart, 2067 01:41:13,160 --> 01:41:15,843 they follow you from page to page to page. 2068 01:41:15,843 --> 01:41:18,260 Heck if you close your browser, come back to the next day, 2069 01:41:18,260 --> 01:41:21,907 they're typically still your shopping cart, which is great for Amazon 2070 01:41:21,907 --> 01:41:23,240 because they want your business. 2071 01:41:23,240 --> 01:41:25,950 They don't want you to have to start from scratch the next day. 2072 01:41:25,950 --> 01:41:29,720 Similarly, when you log into any website these days, 2073 01:41:29,720 --> 01:41:33,530 even if it's not an e-commerce thing but it has usernames and passwords, 2074 01:41:33,530 --> 01:41:35,240 you and I are not in the habit of logging 2075 01:41:35,240 --> 01:41:37,430 into every darn page we visit on a website. 2076 01:41:37,430 --> 01:41:41,420 Typically, you log in once, and then for the next hour, day, week, year, 2077 01:41:41,420 --> 01:41:43,400 you stay logged into that website. 2078 01:41:43,400 --> 01:41:47,540 So somehow, the website is remembering that you have logged in. 2079 01:41:47,540 --> 01:41:50,128 And that is being implemented by way of this thing called 2080 01:41:50,128 --> 01:41:51,920 a session, and perhaps a more familiar term 2081 01:41:51,920 --> 01:41:55,027 that you might know as, and worry about, called cookies. 2082 01:41:55,027 --> 01:41:57,360 Let's go ahead and take one more five minute break here. 2083 01:41:57,360 --> 01:41:59,652 And when we come back, we'll look at cookies, sessions, 2084 01:41:59,652 --> 01:42:01,910 and these final features. 2085 01:42:01,910 --> 01:42:03,190 All right. 2086 01:42:03,190 --> 01:42:06,200 So the promise now is that we're going to implement 2087 01:42:06,200 --> 01:42:09,620 this notion of a session, which is going to allow us to log users in and keep 2088 01:42:09,620 --> 01:42:12,500 them logged in and even implement things like a shopping cart. 2089 01:42:12,500 --> 01:42:16,880 And the overarching goal here is to build an application that 2090 01:42:16,880 --> 01:42:18,380 is, quote unquote, "stateful." 2091 01:42:18,380 --> 01:42:21,560 Again, state refers to information, and something that's stateful 2092 01:42:21,560 --> 01:42:23,240 remembers information. 2093 01:42:23,240 --> 01:42:27,950 And in this context, the curiosity is that HTTP is technically 2094 01:42:27,950 --> 01:42:29,510 a stateless protocol. 2095 01:42:29,510 --> 01:42:33,620 Once you visit a URL, http://something, hit Enter, 2096 01:42:33,620 --> 01:42:36,710 web page is downloaded to your browser, like that's it. 2097 01:42:36,710 --> 01:42:39,710 You can unplug from the internet, you can turn off your Wi-Fi, 2098 01:42:39,710 --> 01:42:42,230 but you still have the web page locally. 2099 01:42:42,230 --> 01:42:45,410 And yet we somehow want to make sure that the next time you 2100 01:42:45,410 --> 01:42:48,060 click on a link on that website, it doesn't forget who you are. 2101 01:42:48,060 --> 01:42:50,060 Or the next thing you add to your shopping cart, 2102 01:42:50,060 --> 01:42:51,870 it doesn't forget what was already there. 2103 01:42:51,870 --> 01:42:55,100 So we somehow want to make HTTP stateful, 2104 01:42:55,100 --> 01:42:58,430 and we can actually do this using the building blocks we've seen thus far. 2105 01:42:58,430 --> 01:43:03,140 So concretely, here's a form you might see occasionally, but pretty rarely, 2106 01:43:03,140 --> 01:43:04,730 when you log into Gmail. 2107 01:43:04,730 --> 01:43:08,660 And I say rarely because most of you don't log into Gmail frequently, 2108 01:43:08,660 --> 01:43:11,690 you just stay logged in, pretty much endlessly, in your browser. 2109 01:43:11,690 --> 01:43:14,390 And that's because Google has made the conscious choice 2110 01:43:14,390 --> 01:43:18,100 to give you a very long session time, maybe a day, a week, 2111 01:43:18,100 --> 01:43:19,850 a month, a year, because they don't really 2112 01:43:19,850 --> 01:43:23,510 want to add friction to using their tool and making you log in every darn day. 2113 01:43:23,510 --> 01:43:26,430 By contrast, there's other applications on campus, 2114 01:43:26,430 --> 01:43:29,270 including some of the CS50 zone, that makes you log in every time. 2115 01:43:29,270 --> 01:43:31,340 Because we want to make sure that it's indeed you 2116 01:43:31,340 --> 01:43:35,280 accessing the site, and not a roommate or friend or someone maliciously. 2117 01:43:35,280 --> 01:43:39,060 So once you do fill out this form, how does Google subsequently 2118 01:43:39,060 --> 01:43:42,390 know that you are you, and when you reload the page even 2119 01:43:42,390 --> 01:43:45,150 or open a second tab for your same Gmail account, 2120 01:43:45,150 --> 01:43:48,907 how do they know that you're still David or Carter or Emma or someone else? 2121 01:43:48,907 --> 01:43:51,240 Well, let's look underneath the hood of what's going on. 2122 01:43:51,240 --> 01:43:54,690 When you log into Gmail, essentially, you initially 2123 01:43:54,690 --> 01:43:57,420 see a form like this using a GET request. 2124 01:43:57,420 --> 01:44:00,090 And the website responds like we saw last week 2125 01:44:00,090 --> 01:44:01,510 with some kind of HTTP response. 2126 01:44:01,510 --> 01:44:03,630 Hopefully 200 OK with the form. 2127 01:44:03,630 --> 01:44:08,460 Meanwhile, the website might also respond with an HTTP header 2128 01:44:08,460 --> 01:44:11,670 that, last week we didn't care about, this week, we now do. 2129 01:44:11,670 --> 01:44:15,240 Whenever you visit a website, it is very commonly the case 2130 01:44:15,240 --> 01:44:18,310 that the website is putting a cookie on your computer. 2131 01:44:18,310 --> 01:44:20,910 And you may generally know that cookies can be bad 2132 01:44:20,910 --> 01:44:25,650 and they track you in some way, and that's both a blessing and a curse. 2133 01:44:25,650 --> 01:44:31,050 Without cookies, you could not implement things like shopping carts and log-ins 2134 01:44:31,050 --> 01:44:32,580 as we know them today. 2135 01:44:32,580 --> 01:44:34,980 Unfortunately, they can also be used for ill purposes 2136 01:44:34,980 --> 01:44:38,280 like tracking you on every website and serving you ads more effectively and so 2137 01:44:38,280 --> 01:44:38,780 forth. 2138 01:44:38,780 --> 01:44:40,710 So with good comes some bad. 2139 01:44:40,710 --> 01:44:43,890 But the basic primitive for us, the computer scientist, 2140 01:44:43,890 --> 01:44:46,860 boils down to just HTTP headers. 2141 01:44:46,860 --> 01:44:51,750 A cookie is typically a big number, a big, seemingly random value, 2142 01:44:51,750 --> 01:44:55,980 that a server tells your browser to store in memory, or even 2143 01:44:55,980 --> 01:44:57,640 longer term, store on disk. 2144 01:44:57,640 --> 01:45:01,180 So you can think of it like a file that a server is planting on your computer. 2145 01:45:01,180 --> 01:45:05,250 And the promise that HTTP makes is that if a server sets 2146 01:45:05,250 --> 01:45:08,220 a cookie on your computer, you will represent 2147 01:45:08,220 --> 01:45:12,220 that same cookie or that same value on every subsequent request. 2148 01:45:12,220 --> 01:45:14,100 So when you visit the website like Gmail, 2149 01:45:14,100 --> 01:45:17,850 they plop a cookie on your computer like this with some session 2150 01:45:17,850 --> 01:45:19,980 equals value, some long random value. 2151 01:45:19,980 --> 01:45:22,310 One, two, three, A, B, C, something like that. 2152 01:45:22,310 --> 01:45:26,730 And when you then visit another page on gmail.com or any other website, 2153 01:45:26,730 --> 01:45:31,590 you send the opposite header, not set cookie, but just cookie colon, 2154 01:45:31,590 --> 01:45:33,610 and you send the exact same value. 2155 01:45:33,610 --> 01:45:36,017 It's similar to going to a club or an amusement park 2156 01:45:36,017 --> 01:45:38,100 where you pay once, you go through the gates once, 2157 01:45:38,100 --> 01:45:40,020 you get checked by security once, and then 2158 01:45:40,020 --> 01:45:44,910 they very often take like a little stamp and say, OK, now you can come and go. 2159 01:45:44,910 --> 01:45:47,743 And then for you, efficiency-wise, if you come back later in the day 2160 01:45:47,743 --> 01:45:50,077 or later in the evening, you can just present your hand. 2161 01:45:50,077 --> 01:45:51,690 You've been stamped, presumably. 2162 01:45:51,690 --> 01:45:54,360 They've already-- you've already paid, you've 2163 01:45:54,360 --> 01:45:55,900 already been searched or whatnot. 2164 01:45:55,900 --> 01:45:57,870 And so it's this sort of fast track ticket 2165 01:45:57,870 --> 01:45:59,700 back into the club, back into the park. 2166 01:45:59,700 --> 01:46:03,480 That's essentially what a cookie is doing for you, whereby 2167 01:46:03,480 --> 01:46:06,060 it's a way of reminding the website we've already done this, 2168 01:46:06,060 --> 01:46:08,290 you already asked me for my username and password. 2169 01:46:08,290 --> 01:46:10,770 This is my path to now come and go. 2170 01:46:10,770 --> 01:46:14,760 Now, unlike this hand stamp, which can be easily copied or transferred 2171 01:46:14,760 --> 01:46:17,370 or duplicated or kept on over multiple days, 2172 01:46:17,370 --> 01:46:22,180 these cookies are really big, seemingly random values, letters and numbers. 2173 01:46:22,180 --> 01:46:24,900 So statistically, there's no way someone else 2174 01:46:24,900 --> 01:46:28,110 is just going to guess your cookie value and pretend to be you It's just 2175 01:46:28,110 --> 01:46:31,110 very low probability, statistically. 2176 01:46:31,110 --> 01:46:34,950 But this is all it boils down to is this agreement between browser and server 2177 01:46:34,950 --> 01:46:39,010 to send these values back and forth in this way. 2178 01:46:39,010 --> 01:46:41,370 So when we actually translate this, now, to code, 2179 01:46:41,370 --> 01:46:43,470 let's do something like a simple login app. 2180 01:46:43,470 --> 01:46:46,590 Let me go into a folder I made in advance today called login. 2181 01:46:46,590 --> 01:46:51,160 And let me code up app.py and let's take a look in here. 2182 01:46:51,160 --> 01:46:52,710 So what's going on? 2183 01:46:52,710 --> 01:46:54,150 A couple of new things up top. 2184 01:46:54,150 --> 01:46:59,040 If I want to have the ability to stamp my users hands, virtually, 2185 01:46:59,040 --> 01:47:02,850 and implement sessions, I'm going to have to import from Flask support 2186 01:47:02,850 --> 01:47:03,790 for sessions. 2187 01:47:03,790 --> 01:47:06,810 So this is another feature you get for free by using a framework 2188 01:47:06,810 --> 01:47:09,040 and not having to implement all this yourself. 2189 01:47:09,040 --> 01:47:11,190 And from the Flask session library, I'm going 2190 01:47:11,190 --> 01:47:13,740 to import Session, capital S. Why? 2191 01:47:13,740 --> 01:47:15,990 I'm going to configure the session as follows. 2192 01:47:15,990 --> 01:47:18,990 Long story short, there's different ways to implement sessions. 2193 01:47:18,990 --> 01:47:22,950 The server can store these cookies in a database, in a file, 2194 01:47:22,950 --> 01:47:25,390 in memory, in RAM, in other places too. 2195 01:47:25,390 --> 01:47:30,220 We are telling it to store these cookies on the server's hard drive. 2196 01:47:30,220 --> 01:47:33,690 So in fact, whenever you use sessions as you will for problem set nine, 2197 01:47:33,690 --> 01:47:37,530 you'll actually see a folder suddenly appear called Flask_session, 2198 01:47:37,530 --> 01:47:40,080 inside of which are the cookies, essentially, 2199 01:47:40,080 --> 01:47:42,450 for any users or friends or yourself who've been 2200 01:47:42,450 --> 01:47:45,040 visiting your particular application. 2201 01:47:45,040 --> 01:47:46,800 So I'm setting it to use the file system, 2202 01:47:46,800 --> 01:47:49,008 and I don't want them to be permanent because I want, 2203 01:47:49,008 --> 01:47:51,720 when you close your browser, the session to go away. 2204 01:47:51,720 --> 01:47:54,270 They could be made to be permanent and last much longer. 2205 01:47:54,270 --> 01:47:56,460 Then I tell my app to support sessions. 2206 01:47:56,460 --> 01:47:58,140 And that's it for now. 2207 01:47:58,140 --> 01:48:01,810 Let's see what this application actually does before we dissect the code. 2208 01:48:01,810 --> 01:48:07,140 Let me go over to my terminal window, run Flask run, and then let me go ahead 2209 01:48:07,140 --> 01:48:11,440 and reload my preview URL. 2210 01:48:11,440 --> 01:48:13,740 Give it a second to kick back in. 2211 01:48:13,740 --> 01:48:15,600 Let me go ahead and open my URL. 2212 01:48:15,600 --> 01:48:17,550 Come on. 2213 01:48:17,550 --> 01:48:20,557 Oops, let me go ahead. 2214 01:48:20,557 --> 01:48:21,390 Too long of a break. 2215 01:48:21,390 --> 01:48:22,030 There we go. 2216 01:48:22,030 --> 01:48:24,465 So this website simply has a login form. 2217 01:48:24,465 --> 01:48:26,340 There's no password, though I could certainly 2218 01:48:26,340 --> 01:48:28,140 add that and check for that too. 2219 01:48:28,140 --> 01:48:29,650 It just asks for your name. 2220 01:48:29,650 --> 01:48:32,310 So I'm going to log in as myself, David, and click Login. 2221 01:48:32,310 --> 01:48:35,130 And now notice I'm currently at the /login route. 2222 01:48:35,130 --> 01:48:36,120 But notice this. 2223 01:48:36,120 --> 01:48:38,445 If I try to go to the default route, just, 2224 01:48:38,445 --> 01:48:41,070 slash, which is where most websites live by default, 2225 01:48:41,070 --> 01:48:44,010 notice that I magically get redirected to log in. 2226 01:48:44,010 --> 01:48:47,160 So somehow, my code knows, hey, if you're not logged in, you're going 2227 01:48:47,160 --> 01:48:48,930 to /login instead. 2228 01:48:48,930 --> 01:48:51,540 Let me type in my name, David, and click Login. 2229 01:48:51,540 --> 01:48:54,345 And now notice I am back at slash. 2230 01:48:54,345 --> 01:48:57,570 Chrome is sort of annoyingly hiding it, but this is the same thing as just 2231 01:48:57,570 --> 01:48:58,720 a single slash. 2232 01:48:58,720 --> 01:49:01,470 And now notice it says you are logged in as David. 2233 01:49:01,470 --> 01:49:02,130 Log out. 2234 01:49:02,130 --> 01:49:05,400 What's cool is notice if I reload the page, it still knows that. 2235 01:49:05,400 --> 01:49:08,820 If I create a second tab and go to the same URL, it still knows that. 2236 01:49:08,820 --> 01:49:10,532 I could even-- 2237 01:49:10,532 --> 01:49:12,240 I could keep doing this in multiple tabs, 2238 01:49:12,240 --> 01:49:15,960 it's still going to remember me on both of them as being logged in as David. 2239 01:49:15,960 --> 01:49:17,290 So how does that work? 2240 01:49:17,290 --> 01:49:22,380 Especially when I click Log Out, then I get forgotten altogether. 2241 01:49:22,380 --> 01:49:24,030 All right, so let's see how this works. 2242 01:49:24,030 --> 01:49:25,980 And it's some basic building blocks. 2243 01:49:25,980 --> 01:49:29,790 Under my /route, notice I have this. 2244 01:49:29,790 --> 01:49:34,660 If there is no name in the session, redirect the user to /login. 2245 01:49:34,660 --> 01:49:37,230 So these two lines together are what implement 2246 01:49:37,230 --> 01:49:41,850 that automatic redirection using HTTP 301 or 302 automatically. 2247 01:49:41,850 --> 01:49:43,930 It's handled for me with these two lines. 2248 01:49:43,930 --> 01:49:45,590 Otherwise, show index.html. 2249 01:49:45,590 --> 01:49:47,340 All right, let's go down that rabbit hole. 2250 01:49:47,340 --> 01:49:48,990 What's in index.html? 2251 01:49:48,990 --> 01:49:52,230 Well, if I look in my-- 2252 01:49:52,230 --> 01:49:58,890 let me look in my templates folder for my login demo and look 2253 01:49:58,890 --> 01:50:02,280 at templates/index.html. 2254 01:50:02,280 --> 01:50:03,870 All right, so what's going on here? 2255 01:50:03,870 --> 01:50:08,460 I extend layout.html, I have a block body, 2256 01:50:08,460 --> 01:50:10,200 and then I've got some other syntax. 2257 01:50:10,200 --> 01:50:12,742 So we haven't seen this yet, but it's more Jinja stuff, which 2258 01:50:12,742 --> 01:50:14,460 again, is almost identical to Python. 2259 01:50:14,460 --> 01:50:17,550 If there's a name in the session variable, 2260 01:50:17,550 --> 01:50:22,320 then literally say you are logged in as curly braces session bracket name. 2261 01:50:22,320 --> 01:50:26,880 And then notice this, I've got a simple HTML link to log out via /logout. 2262 01:50:26,880 --> 01:50:29,550 Else, if there is no name in the session, 2263 01:50:29,550 --> 01:50:33,360 then it apparently says you are not logged in and it leads me to an HTML 2264 01:50:33,360 --> 01:50:35,850 link to /login and then end diff. 2265 01:50:35,850 --> 01:50:38,460 So again, Jinja does not rely on indentation. 2266 01:50:38,460 --> 01:50:41,460 Recall the HTML and CSS don't really care about indentation, 2267 01:50:41,460 --> 01:50:42,690 only the human does. 2268 01:50:42,690 --> 01:50:46,260 But in code with Jinja, you need these end tags, 2269 01:50:46,260 --> 01:50:49,110 end block, end for, end if, to make super obvious 2270 01:50:49,110 --> 01:50:51,330 that you're done with that thought. 2271 01:50:51,330 --> 01:50:54,840 So session is just this magic variable that we now 2272 01:50:54,840 --> 01:50:59,130 have access to because we've included these two lines of code 2273 01:50:59,130 --> 01:51:04,140 and these that handle that whole process of stamping every user's hand 2274 01:51:04,140 --> 01:51:06,090 with a different, unique identifier. 2275 01:51:06,090 --> 01:51:08,760 If I made my code space public and I let all of you 2276 01:51:08,760 --> 01:51:12,270 visit the exact same URL, all of you would be logged out by default. 2277 01:51:12,270 --> 01:51:14,340 You could all type your own names individually, 2278 01:51:14,340 --> 01:51:18,330 all log in at the same URL using different sessions. 2279 01:51:18,330 --> 01:51:21,570 And in fact, I would then see, if I go into my terminal window 2280 01:51:21,570 --> 01:51:26,230 here and my login directory, notice the Flask session directory I mentioned. 2281 01:51:26,230 --> 01:51:30,120 And if I CD into that and type ls, notice that I had two tabs open, 2282 01:51:30,120 --> 01:51:32,790 or actually, I think I started the server twice. 2283 01:51:32,790 --> 01:51:34,180 I have two files in there. 2284 01:51:34,180 --> 01:51:36,930 I would ultimately have one file for every one of you. 2285 01:51:36,930 --> 01:51:38,940 And that's what's beautiful about sessions 2286 01:51:38,940 --> 01:51:43,530 is it creates the illusion of per user storage. 2287 01:51:43,530 --> 01:51:47,860 Inside of my session is my name, inside of your session, so to speak, 2288 01:51:47,860 --> 01:51:48,720 is your name. 2289 01:51:48,720 --> 01:51:52,750 And the same is going to apply to shopping carts, ultimately, as well. 2290 01:51:52,750 --> 01:51:54,450 Let's see how login works here. 2291 01:51:54,450 --> 01:51:58,860 My login route supports both GET and POST, so I could play around if I want. 2292 01:51:58,860 --> 01:52:03,430 And notice this, this login route is kind of interesting as follows. 2293 01:52:03,430 --> 01:52:07,633 If the user got to this route via POST, my inference 2294 01:52:07,633 --> 01:52:09,300 is that they must have submitted a form. 2295 01:52:09,300 --> 01:52:09,800 Why? 2296 01:52:09,800 --> 01:52:13,230 Because that's how I'm going to design the HTML form in a second. 2297 01:52:13,230 --> 01:52:15,870 And if they did submit the form via POST, 2298 01:52:15,870 --> 01:52:18,930 I'm going to store, in the session, at the name 2299 01:52:18,930 --> 01:52:21,330 key, whatever the human's name is. 2300 01:52:21,330 --> 01:52:23,505 And then, I'm going to redirect them back to slash. 2301 01:52:23,505 --> 01:52:26,590 Otherwise, I'm going to show them the login form. 2302 01:52:26,590 --> 01:52:27,870 So this is what's cool. 2303 01:52:27,870 --> 01:52:31,200 If I go to this login form, which lives at, 2304 01:52:31,200 --> 01:52:35,100 literally, slash login, by default, when you visit a URL like that, 2305 01:52:35,100 --> 01:52:36,960 you're visiting via GET. 2306 01:52:36,960 --> 01:52:39,120 And so that's why I see the form. 2307 01:52:39,120 --> 01:52:40,650 However, notice this. 2308 01:52:40,650 --> 01:52:44,550 The form, very cleverly, submits to itself, 2309 01:52:44,550 --> 01:52:49,230 like the one route/login submits to its same self, /login, 2310 01:52:49,230 --> 01:52:51,820 but it uses POST when you submit the form. 2311 01:52:51,820 --> 01:52:55,950 And this is a nice way of having one route but for two different types 2312 01:52:55,950 --> 01:52:58,380 of operations or views. 2313 01:52:58,380 --> 01:53:02,890 When I'm just there visiting /login via URL, it shows me the form. 2314 01:53:02,890 --> 01:53:07,980 But if I submit the form, then this logic, these three lines, kick in, 2315 01:53:07,980 --> 01:53:11,970 and this just avoids my having to have both an index route and a greet route, 2316 01:53:11,970 --> 01:53:12,540 for instance. 2317 01:53:12,540 --> 01:53:17,640 I can just have one route that handles both GET and POST. 2318 01:53:17,640 --> 01:53:18,450 How about logout? 2319 01:53:18,450 --> 01:53:19,420 What does this do? 2320 01:53:19,420 --> 01:53:21,030 Well, it's as simple as this. 2321 01:53:21,030 --> 01:53:23,460 Change whatever name is in the session to be 2322 01:53:23,460 --> 01:53:27,690 none, which is Python's version of null, essentially, and then redirect the user 2323 01:53:27,690 --> 01:53:28,320 back to slash. 2324 01:53:28,320 --> 01:53:34,390 Because now, in index.html, I will not notice a name there anymore. 2325 01:53:34,390 --> 01:53:35,710 This will be false. 2326 01:53:35,710 --> 01:53:39,160 And so I'll tell the user instead, you are not logged in. 2327 01:53:39,160 --> 01:53:40,613 So like it's-- 2328 01:53:40,613 --> 01:53:42,780 I want to say as simple as this is, though I realize 2329 01:53:42,780 --> 01:53:44,640 this is a bunch of steps involved. 2330 01:53:44,640 --> 01:53:47,820 This is the essence of every website on the internet that 2331 01:53:47,820 --> 01:53:49,190 has usernames and passwords. 2332 01:53:49,190 --> 01:53:52,440 And we skip the password name step for that, more on that in problem set nine, 2333 01:53:52,440 --> 01:53:56,850 but this is how every website out there remembers that you're logged in. 2334 01:53:56,850 --> 01:53:59,460 And how this works, ultimately, is that as soon 2335 01:53:59,460 --> 01:54:03,240 as you use in Python lines like this and lines like this, 2336 01:54:03,240 --> 01:54:07,380 Flask takes care of stamping the virtual hand of all of your users 2337 01:54:07,380 --> 01:54:12,630 and whenever Flask sees the same cookie coming back from a user, 2338 01:54:12,630 --> 01:54:15,870 it grabs the appropriate file from that folder, 2339 01:54:15,870 --> 01:54:18,280 loads it into the session global variable 2340 01:54:18,280 --> 01:54:23,250 so that your code is now unique to that user and their name. 2341 01:54:23,250 --> 01:54:26,160 Let's do one other example with sessions here 2342 01:54:26,160 --> 01:54:28,890 that'll show how we might use these, now, for shopping carts. 2343 01:54:28,890 --> 01:54:31,380 Let me go into the store example here. 2344 01:54:31,380 --> 01:54:33,210 Let me go ahead and run this thing first. 2345 01:54:33,210 --> 01:54:39,090 If I run store in my same tab and go back over here, 2346 01:54:39,090 --> 01:54:42,120 we'll see a very ugly e-commerce site that 2347 01:54:42,120 --> 01:54:44,010 just sells seven different books here. 2348 01:54:44,010 --> 01:54:48,497 But each of these books has a button via which I can add it to my cart. 2349 01:54:48,497 --> 01:54:50,580 All right, well where are these books coming from? 2350 01:54:50,580 --> 01:54:51,600 Well, let's poke around. 2351 01:54:51,600 --> 01:54:54,990 Let me go into my terminal window again. 2352 01:54:54,990 --> 01:54:58,230 Let me go into this example, which is called store, 2353 01:54:58,230 --> 01:55:03,150 and let me open up about index dot ht-- whoops. 2354 01:55:03,150 --> 01:55:10,620 Let's open up index, how about, books.html 2355 01:55:10,620 --> 01:55:12,910 is the default one, not index this time. 2356 01:55:12,910 --> 01:55:17,700 So if I look here, notice that that route that we just saw 2357 01:55:17,700 --> 01:55:22,410 uses a for loop in Jinja to iterate over a whole bunch of books, apparently, 2358 01:55:22,410 --> 01:55:25,770 and it outputs, in an H2 tag, the title of the book, 2359 01:55:25,770 --> 01:55:27,960 and then another one of these forms. 2360 01:55:27,960 --> 01:55:29,320 So that's interesting. 2361 01:55:29,320 --> 01:55:30,310 Let's go back one step. 2362 01:55:30,310 --> 01:55:34,230 Let's go ahead and open up app.py, because that must be-- excuse me, 2363 01:55:34,230 --> 01:55:35,670 what's ticking all of this off. 2364 01:55:35,670 --> 01:55:39,090 Notice that this file is importing session support. 2365 01:55:39,090 --> 01:55:42,090 It's configuring sessions down here, but it's also 2366 01:55:42,090 --> 01:55:44,530 connecting to a store.db file. 2367 01:55:44,530 --> 01:55:46,080 So it's adding some SQLite. 2368 01:55:46,080 --> 01:55:51,600 And notice this, in my /route, I'm selecting star from books, 2369 01:55:51,600 --> 01:55:53,880 which is going to give me a list of dictionaries, 2370 01:55:53,880 --> 01:55:55,890 each of which represents a row of books. 2371 01:55:55,890 --> 01:56:00,120 And I'm going to pass that list of books into my books.html template, which 2372 01:56:00,120 --> 01:56:03,840 is why this for loop works the way it does. 2373 01:56:03,840 --> 01:56:05,520 Let's look at this actual database. 2374 01:56:05,520 --> 01:56:10,710 Let me increase my terminal window and do SQLite of store.db.schema 2375 01:56:10,710 --> 01:56:11,760 will show me everything. 2376 01:56:11,760 --> 01:56:13,120 There's not much there. 2377 01:56:13,120 --> 01:56:17,770 It's a book-- it's a table called books with two columns, ID and title. 2378 01:56:17,770 --> 01:56:20,790 Let's do select star from books semicolon. 2379 01:56:20,790 --> 01:56:23,550 There are the seven books, each of which has a unique ID. 2380 01:56:23,550 --> 01:56:25,480 And you might see where this is going. 2381 01:56:25,480 --> 01:56:29,040 If I go to the UI and I look at each of these buttons 2382 01:56:29,040 --> 01:56:34,200 for add to cart, just like Amazon might have, notice that each of these buttons 2383 01:56:34,200 --> 01:56:35,550 is just a form. 2384 01:56:35,550 --> 01:56:37,503 And what's magical here, just like deregister, 2385 01:56:37,503 --> 01:56:39,420 even though I didn't highlight it at the time, 2386 01:56:39,420 --> 01:56:41,580 there's another type of input that allows 2387 01:56:41,580 --> 01:56:45,480 you to specify a value without the human being able easily to change it. 2388 01:56:45,480 --> 01:56:48,270 Instead of type equals text or type equals submit, 2389 01:56:48,270 --> 01:56:53,230 type equals hidden will put the value in the form but not reveal it to the user. 2390 01:56:53,230 --> 01:56:56,340 So that's how I'm saying that the idea of this book is one, 2391 01:56:56,340 --> 01:57:00,550 the idea of this book is two, the idea of this book is three, and so forth. 2392 01:57:00,550 --> 01:57:03,120 And each of these forms, then, will submit, apparently, 2393 01:57:03,120 --> 01:57:08,080 to /cart using POST and that would seem to be what adds things to cart. 2394 01:57:08,080 --> 01:57:08,830 So let's try this. 2395 01:57:08,830 --> 01:57:10,860 Let me click on one or two of these. 2396 01:57:10,860 --> 01:57:13,830 Let's add the first book, add to cart. 2397 01:57:13,830 --> 01:57:14,880 Here's my cart. 2398 01:57:14,880 --> 01:57:17,160 Notice my route change to /cart. 2399 01:57:17,160 --> 01:57:21,120 All right, let's go back and let's add the book number two. 2400 01:57:21,120 --> 01:57:22,110 There we have that one. 2401 01:57:22,110 --> 01:57:25,110 And let's skip ahead to the seventh book, Deathly Hallows, 2402 01:57:25,110 --> 01:57:27,850 and now we have all three books here. 2403 01:57:27,850 --> 01:57:31,530 So what does the cart route do at /cart? 2404 01:57:31,530 --> 01:57:32,280 Well, let's look. 2405 01:57:32,280 --> 01:57:37,590 If I go back to my terminal window, look at app.py and look at /cart, OK, 2406 01:57:37,590 --> 01:57:39,960 there's a lot going on here, but let's see. 2407 01:57:39,960 --> 01:57:43,530 So the /cart route supports both GET or POST, 2408 01:57:43,530 --> 01:57:47,130 which is a nice way to consolidate things into one URL. 2409 01:57:47,130 --> 01:57:49,030 All right, this is interesting. 2410 01:57:49,030 --> 01:57:53,183 If there is not a, quote unquote, "cart" key in session, 2411 01:57:53,183 --> 01:57:54,850 we haven't technically seen this syntax. 2412 01:57:54,850 --> 01:57:59,010 But long story short, these lines here do ensure that the cart exists. 2413 01:57:59,010 --> 01:58:00,220 What do I mean by that? 2414 01:58:00,220 --> 01:58:05,400 It makes sure that there's a cart key in the session, global variable, 2415 01:58:05,400 --> 01:58:07,980 and it's by default going to be an empty list. 2416 01:58:07,980 --> 01:58:08,520 Why? 2417 01:58:08,520 --> 01:58:10,520 That just means you have an empty shopping cart. 2418 01:58:10,520 --> 01:58:17,850 But if the user visits this route via POST and the user did provide an ID, 2419 01:58:17,850 --> 01:58:21,480 they didn't muck with the form in any way and try to hack into the website, 2420 01:58:21,480 --> 01:58:24,930 they gave me a valid ID, then I'm going to use this syntax. 2421 01:58:24,930 --> 01:58:27,780 If session bracket cart is a list-- 2422 01:58:27,780 --> 01:58:30,085 recall from a couple of weeks ago that dot append just 2423 01:58:30,085 --> 01:58:31,210 adds something to the list. 2424 01:58:31,210 --> 01:58:35,440 So I'm going to add the ID to the list and return the user to cart. 2425 01:58:35,440 --> 01:58:40,850 Otherwise, if the user is at /cart via GET, implicitly, we just do this. 2426 01:58:40,850 --> 01:58:44,330 Select star from books where ID is in. 2427 01:58:44,330 --> 01:58:47,170 And this might be syntax you recall from Pset six. 2428 01:58:47,170 --> 01:58:49,780 It lets you look for multiple IDs all at once, 2429 01:58:49,780 --> 01:58:52,000 because if I have a list of session-- 2430 01:58:52,000 --> 01:58:56,470 list of IDs in my cart, I can get all of those books at once. 2431 01:58:56,470 --> 01:58:59,170 So long story short, what has happened here? 2432 01:58:59,170 --> 01:59:05,170 I am storing, in the cart, the books that I myself have added to my cart. 2433 01:59:05,170 --> 01:59:08,030 My browser is sending the same hand stamp again and again, 2434 01:59:08,030 --> 01:59:11,150 which is how this website knows that it's me adding these books to my cart 2435 01:59:11,150 --> 01:59:12,940 and not you or not Carter or not Emma. 2436 01:59:12,940 --> 01:59:16,240 Indeed, if all of us visited the same long URL and I made it public 2437 01:59:16,240 --> 01:59:19,030 and allowed that, then we would all have our own illusions 2438 01:59:19,030 --> 01:59:20,650 of our own separate carts. 2439 01:59:20,650 --> 01:59:23,140 And each of those carts, in practice, would just 2440 01:59:23,140 --> 01:59:26,920 be stored in this Flask session directory on the server 2441 01:59:26,920 --> 01:59:28,720 so that the server can keep track of each 2442 01:59:28,720 --> 01:59:31,690 of us using, again, these cookie values that are being 2443 01:59:31,690 --> 01:59:35,420 sent back and forth via these headers. 2444 01:59:35,420 --> 01:59:35,920 All right. 2445 01:59:35,920 --> 01:59:38,230 I know that's a lot, but again, it's just 2446 01:59:38,230 --> 01:59:41,710 the new Python way of just leveraging those HTTP 2447 01:59:41,710 --> 01:59:44,360 headers from last week in a clever way. 2448 01:59:44,360 --> 01:59:48,340 Any questions before we look at one final set of examples? 2449 01:59:48,340 --> 01:59:49,648 Yeah. 2450 01:59:49,648 --> 01:59:53,560 AUDIENCE: [INAUDIBLE] understand how a log in has to do with [INAUDIBLE]?? 2451 01:59:53,560 --> 01:59:56,983 How does it use [INAUDIBLE],, how do you change [INAUDIBLE]?? 2452 01:59:56,983 --> 02:00:01,384 Because in order to use a GET request dot [INAUDIBLE] equals, 2453 02:00:01,384 --> 02:00:05,320 there has to be an exchange in [INAUDIBLE].. 2454 02:00:05,320 --> 02:00:08,530 DAVID: So I think you're asking about using the GET 2455 02:00:08,530 --> 02:00:10,700 and POST in the same function. 2456 02:00:10,700 --> 02:00:15,220 So this is just a nice aesthetic, if you will. 2457 02:00:15,220 --> 02:00:18,670 If I had to have separate routes for GET and POST, I mean, 2458 02:00:18,670 --> 02:00:21,430 it literally might mean I need twice as many routes in my file. 2459 02:00:21,430 --> 02:00:23,680 And it just starts to get a little annoying. 2460 02:00:23,680 --> 02:00:26,420 And these days, too, in terms of user experience, 2461 02:00:26,420 --> 02:00:30,400 this is maybe only appeals to the geek in us, but having clean URLs 2462 02:00:30,400 --> 02:00:31,690 is actually a thing. 2463 02:00:31,690 --> 02:00:33,700 You don't want to have lots of words in the URL, 2464 02:00:33,700 --> 02:00:37,160 it's nice if the URLs are nice and succinct and canonical, if you will. 2465 02:00:37,160 --> 02:00:43,270 So it's nice if I can centralize all of my shopping cart functionality in /cart 2466 02:00:43,270 --> 02:00:47,890 only, and not in multiple routes, one for GET, one for POST. 2467 02:00:47,890 --> 02:00:52,250 It's a little nitpicky of me, but this is commonly done here. 2468 02:00:52,250 --> 02:00:56,860 So what this code here means is that this route, this function, 2469 02:00:56,860 --> 02:01:00,460 henceforth will support both GET requests and POST requests. 2470 02:01:00,460 --> 02:01:04,450 But then I need to distinguish between whether it's GET or POST coming in. 2471 02:01:04,450 --> 02:01:07,120 Because if it's a GET request, I want to show the cart. 2472 02:01:07,120 --> 02:01:09,580 If it's a POST request, I want to update the cart. 2473 02:01:09,580 --> 02:01:13,780 And the simplest way to do that is just to check this value here. 2474 02:01:13,780 --> 02:01:17,230 In the request variable that we imported from Flask up above, 2475 02:01:17,230 --> 02:01:20,080 you can check what is the current type of request. 2476 02:01:20,080 --> 02:01:23,170 Is it a GET, is it a POST, or is it something else altogether? 2477 02:01:23,170 --> 02:01:24,820 There are other verbs. 2478 02:01:24,820 --> 02:01:29,890 If it's a POST, that must mean, because I created the web form that uses POST, 2479 02:01:29,890 --> 02:01:33,160 that the user clicked the Add to Cart button. 2480 02:01:33,160 --> 02:01:38,350 Otherwise, if it's not POST, it's implicitly going to be logically GET. 2481 02:01:38,350 --> 02:01:42,610 Then, I just want to show the user the contents of the cart 2482 02:01:42,610 --> 02:01:44,120 and I use these lines instead. 2483 02:01:44,120 --> 02:01:47,920 So it's just one way of avoiding having two routes for two different HTTP 2484 02:01:47,920 --> 02:01:48,430 verbs. 2485 02:01:48,430 --> 02:01:51,340 You can combine them so long as you have a check like this. 2486 02:01:51,340 --> 02:01:57,670 If I really wanted to be pedantic, I could do this elif request.method=get. 2487 02:01:57,670 --> 02:02:00,250 2488 02:02:00,250 --> 02:02:02,830 This would be more symmetric, but it's not really necessary, 2489 02:02:02,830 --> 02:02:05,750 because I know there's only two possibilities. 2490 02:02:05,750 --> 02:02:08,330 Hope that helps. 2491 02:02:08,330 --> 02:02:11,140 All right, let's do one final set of examples here 2492 02:02:11,140 --> 02:02:13,330 that's going to tie the last of these features 2493 02:02:13,330 --> 02:02:15,760 together to something that you probably see 2494 02:02:15,760 --> 02:02:18,612 quite often in real-world applications. 2495 02:02:18,612 --> 02:02:20,320 And that, for better or for worse, is now 2496 02:02:20,320 --> 02:02:23,660 going to involve tying back in some JavaScript from last week. 2497 02:02:23,660 --> 02:02:25,660 The goal at hand of these examples is not 2498 02:02:25,660 --> 02:02:29,043 to necessarily master how you yourself would write the Python code, the SQL 2499 02:02:29,043 --> 02:02:31,960 code, the JavaScript code, but just to give you a mental model for how 2500 02:02:31,960 --> 02:02:33,290 these different languages work. 2501 02:02:33,290 --> 02:02:35,680 So that for final projects, especially if you 2502 02:02:35,680 --> 02:02:39,160 do want to add JavaScript functionality, much more interactive user interface, 2503 02:02:39,160 --> 02:02:42,340 you at least have the bare bones of a mental model for how 2504 02:02:42,340 --> 02:02:44,780 you can tie these languages together. 2505 02:02:44,780 --> 02:02:48,370 Even though our focus, generally, has been more on Python and SQL 2506 02:02:48,370 --> 02:02:50,560 than on JavaScript from last week. 2507 02:02:50,560 --> 02:02:55,660 Let me go ahead and open up an example called shows, version zero of this. 2508 02:02:55,660 --> 02:02:57,260 And let me do Flask run. 2509 02:02:57,260 --> 02:03:01,330 And let me go into my URL here and see what this application looks 2510 02:03:01,330 --> 02:03:06,670 like by default. This has just a simple query text box with a search box. 2511 02:03:06,670 --> 02:03:09,700 Let's take a look at the HTML that just got sent to my browser. 2512 02:03:09,700 --> 02:03:11,810 All right, there's not much going on here at all. 2513 02:03:11,810 --> 02:03:14,920 So there's a form whose action is /search. 2514 02:03:14,920 --> 02:03:16,720 It's going to submit via GET. 2515 02:03:16,720 --> 02:03:21,140 It's going to use a q parameter, just like Google it seems, and submit it. 2516 02:03:21,140 --> 02:03:24,110 So this actually looks like the Google form we did last week. 2517 02:03:24,110 --> 02:03:25,990 So let's see what goes on here. 2518 02:03:25,990 --> 02:03:28,390 Let me search for something like cat. 2519 02:03:28,390 --> 02:03:29,740 Enter. 2520 02:03:29,740 --> 02:03:31,820 OK, so it looks like-- 2521 02:03:31,820 --> 02:03:34,280 all right, so this is actually a somewhat familiar file. 2522 02:03:34,280 --> 02:03:38,470 What I've gone ahead and done is I've grabbed all of the titles of TV shows 2523 02:03:38,470 --> 02:03:41,290 from a couple of weeks ago when we first introduced SQL, 2524 02:03:41,290 --> 02:03:43,840 and I loaded them into this demo so that you can search 2525 02:03:43,840 --> 02:03:45,650 by keyword for any word you want. 2526 02:03:45,650 --> 02:03:46,750 I just searched for cat. 2527 02:03:46,750 --> 02:03:49,900 If we were to do this again, we would see all the title of TV shows 2528 02:03:49,900 --> 02:03:55,100 that contain D-O-G, dog, as a substring somewhere and so forth. 2529 02:03:55,100 --> 02:03:57,130 So this is a traditional way of doing this. 2530 02:03:57,130 --> 02:04:02,740 Just like in Google, it uses /search?q=cat, q=dog, and so forth. 2531 02:04:02,740 --> 02:04:03,620 How does that work? 2532 02:04:03,620 --> 02:04:07,670 Well, let's just take a quick look at app.py here. 2533 02:04:07,670 --> 02:04:12,940 Let me go into my zero example here, show zero, and open up 2534 02:04:12,940 --> 02:04:15,460 app.py and see what's going on. 2535 02:04:15,460 --> 02:04:17,120 All right, very simple. 2536 02:04:17,120 --> 02:04:19,780 Here's the form, that's how we started today. 2537 02:04:19,780 --> 02:04:22,255 And here is the /search route. 2538 02:04:22,255 --> 02:04:23,380 Well, what's going on here? 2539 02:04:23,380 --> 02:04:25,070 This gets a little interesting. 2540 02:04:25,070 --> 02:04:28,270 So I first select a whole bunch of shows by doing this. 2541 02:04:28,270 --> 02:04:32,890 Select star from shows, where title like question mark. 2542 02:04:32,890 --> 02:04:37,570 And then I'm using some percent signs from SQL 2543 02:04:37,570 --> 02:04:40,030 on both the left and the right, and I'm plugging 2544 02:04:40,030 --> 02:04:42,450 in whatever the user's input was for q. 2545 02:04:42,450 --> 02:04:45,040 If I didn't use like and I used equal instead, 2546 02:04:45,040 --> 02:04:48,130 I could get rid of these curly brace, these percent signs, 2547 02:04:48,130 --> 02:04:51,760 but then it would have to be a show called cat or called dog as opposed 2548 02:04:51,760 --> 02:04:54,460 to it being like cat or like dog. 2549 02:04:54,460 --> 02:04:58,030 This whole line returns to me a list of dictionaries, each of which 2550 02:04:58,030 --> 02:05:00,920 represents a show in the database. 2551 02:05:00,920 --> 02:05:04,210 And then, I'm passing all of those shows to a template called search.html. 2552 02:05:04,210 --> 02:05:08,010 So let's just follow that breadcrumb, let's open up shows dot-- 2553 02:05:08,010 --> 02:05:10,390 sorry, search.html. 2554 02:05:10,390 --> 02:05:12,570 All right, so this is where templating gets cool. 2555 02:05:12,570 --> 02:05:15,270 So I just passed back hundreds of results, potentially, 2556 02:05:15,270 --> 02:05:18,750 but the only thing I'm outputting is an unordered list 2557 02:05:18,750 --> 02:05:22,830 and using a Jinja for loop and li tag containing 2558 02:05:22,830 --> 02:05:24,745 the titles of each of those shows. 2559 02:05:24,745 --> 02:05:27,120 And just to prove that this is indeed a familiar data set 2560 02:05:27,120 --> 02:05:32,040 and I actually simplified it a bit, if I look at shows.db with SQLite, 2561 02:05:32,040 --> 02:05:36,330 I threw away all the other stuff like ratings and actors and everyone else 2562 02:05:36,330 --> 02:05:41,070 and I just have, for instance, select star from shows 2563 02:05:41,070 --> 02:05:43,440 limit 10, just so we can see 10 of them. 2564 02:05:43,440 --> 02:05:45,810 There's 10 of the shows from that database. 2565 02:05:45,810 --> 02:05:48,220 So that's all that's in the database itself. 2566 02:05:48,220 --> 02:05:51,810 So it would look like this is a pretty vanilla web application. 2567 02:05:51,810 --> 02:05:53,845 It uses GET, it submits it to the server, 2568 02:05:53,845 --> 02:05:56,220 the server spits out a response, and that response, then, 2569 02:05:56,220 --> 02:06:00,990 looks like this, which is a huge number of li tags, one for each cat 2570 02:06:00,990 --> 02:06:02,700 or one for each dog match. 2571 02:06:02,700 --> 02:06:06,370 But everything else comes from a layout.html. 2572 02:06:06,370 --> 02:06:09,010 All the stuff at the top and at the bottom. 2573 02:06:09,010 --> 02:06:13,020 All right, so these days, though, we're in the habit of seeing autocomplete. 2574 02:06:13,020 --> 02:06:15,720 And you start typing something and you don't have to hit Submit, 2575 02:06:15,720 --> 02:06:18,595 you don't have to click a button, you don't have to go to a new page. 2576 02:06:18,595 --> 02:06:20,950 Web applications, nowadays, are much more dynamic. 2577 02:06:20,950 --> 02:06:24,130 So let's take a look at this version one of this thing. 2578 02:06:24,130 --> 02:06:30,030 Let me go into shows one and close my previous tabs 2579 02:06:30,030 --> 02:06:32,140 and run Flask run in here. 2580 02:06:32,140 --> 02:06:36,840 And it's almost the same thing, but watch the behavior change a little bit. 2581 02:06:36,840 --> 02:06:38,863 I'm reloading the form, there's no button now. 2582 02:06:38,863 --> 02:06:40,530 So gone is the need for a submit button. 2583 02:06:40,530 --> 02:06:42,550 I want to implement autocomplete now. 2584 02:06:42,550 --> 02:06:45,150 So let's go ahead and type in C. OK, there's 2585 02:06:45,150 --> 02:06:48,120 every show that starts with C. A, there's 2586 02:06:48,120 --> 02:06:50,100 every show that has C-A in it, rather. 2587 02:06:50,100 --> 02:06:53,340 T, there's every show with C-A-T in it. 2588 02:06:53,340 --> 02:06:57,150 I can start it again and do dog, but notice how instantaneous it was. 2589 02:06:57,150 --> 02:07:01,050 And notice my URL never changed, there's no /search route, 2590 02:07:01,050 --> 02:07:02,250 and it's just immediate. 2591 02:07:02,250 --> 02:07:05,890 With every keystroke, it is searching again and again and again. 2592 02:07:05,890 --> 02:07:08,520 That's a nice UX, user experience, because it's immediate. 2593 02:07:08,520 --> 02:07:10,770 This is what users are used to these days. 2594 02:07:10,770 --> 02:07:15,630 But if I look at the source code here, notice that in the source code, 2595 02:07:15,630 --> 02:07:20,853 there's just an empty UL by default but there is some fancy JavaScript code. 2596 02:07:20,853 --> 02:07:22,270 So let's see what's going on here. 2597 02:07:22,270 --> 02:07:25,750 This JavaScript code is doing the following. 2598 02:07:25,750 --> 02:07:28,710 Let me zoom in a little bit more. 2599 02:07:28,710 --> 02:07:33,092 This JavaScript code is first selecting, with query selector, 2600 02:07:33,092 --> 02:07:35,800 which you used this past week, quote unquote "input, " all right, 2601 02:07:35,800 --> 02:07:37,740 so that's just getting the text box. 2602 02:07:37,740 --> 02:07:41,375 Then it's adding an event listener to that input for the input event. 2603 02:07:41,375 --> 02:07:43,500 We didn't talk about this last week, but literally, 2604 02:07:43,500 --> 02:07:45,600 when you provide any kind of input by typing, 2605 02:07:45,600 --> 02:07:50,100 by pasting, by any other user interface mechanism, 2606 02:07:50,100 --> 02:07:51,910 it triggers an event called input. 2607 02:07:51,910 --> 02:07:53,970 So similar to key press or key up. 2608 02:07:53,970 --> 02:07:57,780 I then have a function, no worries about this async function for now. 2609 02:07:57,780 --> 02:07:59,482 Then what do I do inside of this? 2610 02:07:59,482 --> 02:08:01,440 All right, so this is new, and this is the part 2611 02:08:01,440 --> 02:08:04,110 that let's just focus on the ideas and not the syntax. 2612 02:08:04,110 --> 02:08:06,000 JavaScript, nowadays, comes with a function 2613 02:08:06,000 --> 02:08:10,290 called fetch that allows you to GET or POST information to a server 2614 02:08:10,290 --> 02:08:12,100 without reloading the whole page. 2615 02:08:12,100 --> 02:08:14,610 You can sort of secretly do it inside of the page. 2616 02:08:14,610 --> 02:08:15,930 What do I want to fetch? 2617 02:08:15,930 --> 02:08:21,270 slash search question mark q equals whatever the value of that input is. 2618 02:08:21,270 --> 02:08:25,320 When I get back a response, I want to get the text of that response 2619 02:08:25,320 --> 02:08:27,570 and store it in a variable called shows. 2620 02:08:27,570 --> 02:08:30,240 And I'm deliberately bouncing around, ignoring special words 2621 02:08:30,240 --> 02:08:33,600 like await and await here, but for now, just focus on what came back. 2622 02:08:33,600 --> 02:08:36,840 A response came back from the server, I'm getting the text from it, 2623 02:08:36,840 --> 02:08:38,670 storing it in a variable called shows. 2624 02:08:38,670 --> 02:08:39,930 What am I then doing? 2625 02:08:39,930 --> 02:08:44,700 I'm using query selector to select my UL, which is empty by default, 2626 02:08:44,700 --> 02:08:48,960 and I'm changing its inner HTML to be equal to the shows that 2627 02:08:48,960 --> 02:08:50,590 came back from the server. 2628 02:08:50,590 --> 02:08:51,810 So let's poke around. 2629 02:08:51,810 --> 02:08:54,640 Here's where, again, developer tools are quite powerful. 2630 02:08:54,640 --> 02:08:58,890 Let me go ahead and reload this page to get rid of everything. 2631 02:08:58,890 --> 02:09:02,190 And let me now open up inspect. 2632 02:09:02,190 --> 02:09:05,530 Let me go to the Network tab and let's just sniff the traffic going 2633 02:09:05,530 --> 02:09:06,780 between my browser and server. 2634 02:09:06,780 --> 02:09:11,460 I'm going to search for C. Notice that immediately triggered an HTTP request 2635 02:09:11,460 --> 02:09:13,530 to /search?q=c. 2636 02:09:13,530 --> 02:09:16,440 2637 02:09:16,440 --> 02:09:20,050 So I didn't even finish my cat thought, but notice what came back. 2638 02:09:20,050 --> 02:09:24,900 A bunch of response headers, but let's actually click on the raw response. 2639 02:09:24,900 --> 02:09:29,550 This is literally the response from the server, just a whole bunch of li tags. 2640 02:09:29,550 --> 02:09:32,610 No UL, no HTML, no title, no body, nothing. 2641 02:09:32,610 --> 02:09:33,690 Just li tags. 2642 02:09:33,690 --> 02:09:35,200 And we can actually simulate this. 2643 02:09:35,200 --> 02:09:39,360 Let me manually go to that same URL, q=c, Enter. 2644 02:09:39,360 --> 02:09:41,370 We are just going to get back-- 2645 02:09:41,370 --> 02:09:42,810 whoops, sorry. 2646 02:09:42,810 --> 02:09:47,670 slash search q equals c, we are just going to get back this stuff, 2647 02:09:47,670 --> 02:09:50,130 which if I view source, it's not even a complete web page. 2648 02:09:50,130 --> 02:09:53,550 The browser is trying to show it to me as a complete web page with bullets, 2649 02:09:53,550 --> 02:09:56,100 but it's really just partial HTML. 2650 02:09:56,100 --> 02:09:58,710 But that's perfect, because this is literally 2651 02:09:58,710 --> 02:10:01,620 what I essentially want my Python code to copy paste 2652 02:10:01,620 --> 02:10:04,710 into the otherwise empty UL tag. 2653 02:10:04,710 --> 02:10:09,060 And that's what this JavaScript code then, here, is doing. 2654 02:10:09,060 --> 02:10:13,350 Once it gets back that response from the server, it's using these lines of code 2655 02:10:13,350 --> 02:10:18,370 to plug all of those li's into the UL after the fact. 2656 02:10:18,370 --> 02:10:20,730 Again, changing the so-called dom. 2657 02:10:20,730 --> 02:10:23,700 But there's a slightly better way to do this because, honestly, this 2658 02:10:23,700 --> 02:10:25,170 is not the best design. 2659 02:10:25,170 --> 02:10:29,490 Because if you've got a hundred shows or more, you're sending all of these tags 2660 02:10:29,490 --> 02:10:30,450 unnecessarily. 2661 02:10:30,450 --> 02:10:33,090 Why do I need to send all of these stupid HTML tags? 2662 02:10:33,090 --> 02:10:36,190 Why don't I just create those when I'm ready to create them? 2663 02:10:36,190 --> 02:10:37,920 Well, here's the final flourish. 2664 02:10:37,920 --> 02:10:40,470 Whenever making a web application nowadays, 2665 02:10:40,470 --> 02:10:44,640 where client and server keep talking to one another, Google Maps does this, 2666 02:10:44,640 --> 02:10:47,430 Gmail does this, literally every cool application 2667 02:10:47,430 --> 02:10:49,770 nowadays you load the page once and then it 2668 02:10:49,770 --> 02:10:51,540 keeps on interacting with you without you 2669 02:10:51,540 --> 02:10:54,210 reloading or having to change the URL. 2670 02:10:54,210 --> 02:10:58,710 Let's actually use a format called JSON, JavaScript Object Notation, which 2671 02:10:58,710 --> 02:11:01,800 is to say there's just a better, more efficient, better 2672 02:11:01,800 --> 02:11:04,390 designed way to send that same data. 2673 02:11:04,390 --> 02:11:08,670 I'm going to go into shows two now and do Flask run. 2674 02:11:08,670 --> 02:11:10,410 And I'm going to go back to my page here. 2675 02:11:10,410 --> 02:11:14,760 The user interface is exactly the same, and it still works exactly the same. 2676 02:11:14,760 --> 02:11:18,790 Here's C, C-A, C-A-T, and so forth. 2677 02:11:18,790 --> 02:11:21,270 But let's see what's coming back now. 2678 02:11:21,270 --> 02:11:31,390 If I go to /search?q=cat, Enter, notice that I get this crazy-looking syntax. 2679 02:11:31,390 --> 02:11:34,860 But the fact that it's so compact is actually a good thing. 2680 02:11:34,860 --> 02:11:38,610 This is actually going to-- let me format it a little nicer, well, 2681 02:11:38,610 --> 02:11:39,690 or a little worse. 2682 02:11:39,690 --> 02:11:42,990 This is what's called JavaScript Object Notation. 2683 02:11:42,990 --> 02:11:48,780 In JavaScript, an angle-- a square bracket means here comes an array. 2684 02:11:48,780 --> 02:11:54,780 In JavaScript, a curly bracket says here comes an object, AKA, a dictionary. 2685 02:11:54,780 --> 02:11:57,840 And you might recall from-- 2686 02:11:57,840 --> 02:11:59,020 did we do? 2687 02:11:59,020 --> 02:12:05,010 Yes, sort of recall that you can now have keys and values in JavaScript 2688 02:12:05,010 --> 02:12:07,360 notation using colons like this. 2689 02:12:07,360 --> 02:12:10,950 So long story short, cryptic as this is to you and me 2690 02:12:10,950 --> 02:12:14,310 and not very human friendly, it's very machine friendly. 2691 02:12:14,310 --> 02:12:18,030 Because for every title in that database, 2692 02:12:18,030 --> 02:12:23,800 I get back its ID and its title, its ID and its title, its ID and its title. 2693 02:12:23,800 --> 02:12:27,870 And this is a very generic format that an API, an application programming 2694 02:12:27,870 --> 02:12:29,340 interface, might return to you. 2695 02:12:29,340 --> 02:12:31,380 And this is how APIs, nowadays, work. 2696 02:12:31,380 --> 02:12:36,120 You get back very raw textual data in this format, JSON format, 2697 02:12:36,120 --> 02:12:39,840 and then you can write code that actually programmatically turns 2698 02:12:39,840 --> 02:12:44,530 that JSON data into any language you want, for instance, HTML. 2699 02:12:44,530 --> 02:12:47,490 So here's the third and final version of this program. 2700 02:12:47,490 --> 02:12:49,590 I, again, select my input. 2701 02:12:49,590 --> 02:12:51,870 I, again, listen for input. 2702 02:12:51,870 --> 02:12:54,690 I then, when I get input, call this function. 2703 02:12:54,690 --> 02:13:01,230 I fetch slash search q equals whatever that input was, C or C-A or C-A-T. 2704 02:13:01,230 --> 02:13:04,193 I then wait for the response, but instead of getting text, 2705 02:13:04,193 --> 02:13:07,110 I'm calling this other function that comes with JavaScript these days, 2706 02:13:07,110 --> 02:13:09,330 called JSON, that just parses that. 2707 02:13:09,330 --> 02:13:13,470 It turns it into a dictionary for me, or really a list of dictionaries for me, 2708 02:13:13,470 --> 02:13:15,810 and stores it in a variable called shows. 2709 02:13:15,810 --> 02:13:20,070 And this is where you start to see the convergence of HTML with JavaScript. 2710 02:13:20,070 --> 02:13:23,400 Let me initialize a variable called HTML to nothing, quote unquote, 2711 02:13:23,400 --> 02:13:26,200 using single quotes, but I could also use double quotes. 2712 02:13:26,200 --> 02:13:28,470 This is JavaScript syntax for a loop. 2713 02:13:28,470 --> 02:13:32,340 Let me iterate over every ID in the show's list 2714 02:13:32,340 --> 02:13:36,120 that I just got back in the server, that big chunk of JSON data. 2715 02:13:36,120 --> 02:13:41,430 Let me create a variable called Title that's equal to the shows-- 2716 02:13:41,430 --> 02:13:43,890 the title of the show at that ID. 2717 02:13:43,890 --> 02:13:45,900 But for reasons we'll come back to, let me 2718 02:13:45,900 --> 02:13:47,820 replace a couple of scary characters. 2719 02:13:47,820 --> 02:13:53,910 Then let me dynamically add to this variable, an li tag, the actual title, 2720 02:13:53,910 --> 02:13:55,470 and a close li tag. 2721 02:13:55,470 --> 02:13:58,230 And then very lastly, after this for loop, 2722 02:13:58,230 --> 02:14:04,320 let me update the ULs in our HTML to be the HTML I just created on the fly. 2723 02:14:04,320 --> 02:14:06,900 So in short, don't worry too much about the syntax 2724 02:14:06,900 --> 02:14:09,358 because you won't need to use this unless you start playing 2725 02:14:09,358 --> 02:14:11,470 with more advanced features quite soon. 2726 02:14:11,470 --> 02:14:13,440 But what we're doing is, with JavaScript, we're 2727 02:14:13,440 --> 02:14:16,360 creating a bigger and bigger and bigger string of HTML 2728 02:14:16,360 --> 02:14:19,800 containing all of the open brackets, the li tags, the closed brackets, 2729 02:14:19,800 --> 02:14:23,160 but we're just grabbing the raw data from the server. 2730 02:14:23,160 --> 02:14:25,170 And so in fact in problem set nine, you're 2731 02:14:25,170 --> 02:14:28,890 going to use a real world third party API, application programming 2732 02:14:28,890 --> 02:14:30,330 interface, for which you sign up. 2733 02:14:30,330 --> 02:14:33,090 The data you're going to get back from that API is not 2734 02:14:33,090 --> 02:14:36,540 going to be show titles, but actually stock quotes and stocks 2735 02:14:36,540 --> 02:14:39,280 ticker symbols and the prices of last-- 2736 02:14:39,280 --> 02:14:41,310 at which stocks were last bought or sold, 2737 02:14:41,310 --> 02:14:44,118 and you're going to get that data back in JSON format. 2738 02:14:44,118 --> 02:14:47,160 And you're going to write a bit of code that's then going to convert that 2739 02:14:47,160 --> 02:14:50,230 to the requisite HTML on the page. 2740 02:14:50,230 --> 02:14:53,520 So the final result here is literally the kind of autocomplete 2741 02:14:53,520 --> 02:14:55,890 that you and I see and take for granted every day, 2742 02:14:55,890 --> 02:14:58,050 and that's ultimately how it works. 2743 02:14:58,050 --> 02:15:01,680 HTML and CSS are used to present the data, your so-called view. 2744 02:15:01,680 --> 02:15:06,100 Python might be used to send or get the data on the backend server. 2745 02:15:06,100 --> 02:15:08,370 And then lastly, JavaScript is going to be used 2746 02:15:08,370 --> 02:15:10,757 to make things dynamic and interactive. 2747 02:15:10,757 --> 02:15:12,840 So I know that's a whole bunch of building blocks, 2748 02:15:12,840 --> 02:15:15,632 but the whole point of problem set nine to tie everything together, 2749 02:15:15,632 --> 02:15:18,150 set the stage for hopefully a very successful final project. 2750 02:15:18,150 --> 02:15:20,400 Why don't we go ahead and wrap up there, and we'll see 2751 02:15:20,400 --> 02:15:23,610 you one last time next week for emoji. 2752 02:15:23,610 --> 02:15:26,960 [MUSIC PLAYING] 2753 02:15:26,960 --> 02:15:58,000 [MUSIC PLAYING] 230664

Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.