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.