1 00:00:00,000 --> 00:00:00,960 BRIAN: All right. 2 00:00:00,960 --> 00:00:04,530 So far, we've been able to use Flask to build web applications. 3 00:00:04,530 --> 00:00:07,620 But so far, the web applications we've been creating 4 00:00:07,620 --> 00:00:10,647 are serving the same files to every user. 5 00:00:10,647 --> 00:00:12,480 But a lot of web applications that you might 6 00:00:12,480 --> 00:00:15,840 have interacted with in social media websites or other websites 7 00:00:15,840 --> 00:00:17,130 let you log in. 8 00:00:17,130 --> 00:00:20,340 You log in once-- and then every time you visit the website again, 9 00:00:20,340 --> 00:00:22,140 it somehow remembers who you are. 10 00:00:22,140 --> 00:00:24,360 You're not prompted to re-log in every time. 11 00:00:24,360 --> 00:00:27,240 It knows who you are so it can to display your news feed 12 00:00:27,240 --> 00:00:30,780 or information that's relevant to you when you visit that web page. 13 00:00:30,780 --> 00:00:32,942 How is it that websites are able to do that? 14 00:00:32,942 --> 00:00:34,650 Well, it turns out that many websites use 15 00:00:34,650 --> 00:00:37,290 a technology called cookies, where cookies are just 16 00:00:37,290 --> 00:00:41,790 data that a website can ask your web browser to store on your computer 17 00:00:41,790 --> 00:00:43,650 such that it's stored in your computer. 18 00:00:43,650 --> 00:00:46,920 And the next time that your web browser visits that same website, 19 00:00:46,920 --> 00:00:50,120 your web browser can show the cookie to the website 20 00:00:50,120 --> 00:00:52,500 so that the website knows who you are again. 21 00:00:52,500 --> 00:00:56,610 It's an identifying piece of information such that after you log in once, 22 00:00:56,610 --> 00:00:58,830 some cookie is stored inside your web browser. 23 00:00:58,830 --> 00:01:01,140 And the next time you visit that same website, 24 00:01:01,140 --> 00:01:03,480 you can present that cookie to the web server 25 00:01:03,480 --> 00:01:07,470 so the web server knows who you are and knows what information to then display 26 00:01:07,470 --> 00:01:08,460 to you. 27 00:01:08,460 --> 00:01:11,610 This allows for the notion of what we're going to call sessions-- 28 00:01:11,610 --> 00:01:16,410 some data about your current interaction with a website that is specific to you. 29 00:01:16,410 --> 00:01:20,010 And so let's take a look at how we can add sessions to our web application 30 00:01:20,010 --> 00:01:21,190 now. 31 00:01:21,190 --> 00:01:24,090 So what we're looking at here in CS50 IDE 32 00:01:24,090 --> 00:01:27,600 is the same task management application that we created earlier 33 00:01:27,600 --> 00:01:30,870 when we were creating our first web applications using Flask, 34 00:01:30,870 --> 00:01:33,870 where we would create an application that displayed a list of the things 35 00:01:33,870 --> 00:01:35,010 that you need to do. 36 00:01:35,010 --> 00:01:38,550 And then give you a page where you could add a new task to that list of things 37 00:01:38,550 --> 00:01:39,780 that you need to do. 38 00:01:39,780 --> 00:01:42,870 Let's take a look at how this application works, just to recall. 39 00:01:42,870 --> 00:01:44,860 So here's our page with all our tasks. 40 00:01:44,860 --> 00:01:48,400 And if we create a new task, just call it foo, and press Submit. 41 00:01:48,400 --> 00:01:51,480 I'll create another task, call it bar, and Submit. 42 00:01:51,480 --> 00:01:53,790 All right, I have two tasks now. 43 00:01:53,790 --> 00:01:57,240 But the interesting thing about this is that currently this data is just 44 00:01:57,240 --> 00:02:01,440 stored as a global variable inside of our Flask application, 45 00:02:01,440 --> 00:02:05,370 which means that it's shared among all of the people that might conceivably 46 00:02:05,370 --> 00:02:07,260 be using this application. 47 00:02:07,260 --> 00:02:09,840 If another person were to open up this page, which 48 00:02:09,840 --> 00:02:13,810 I can simulate by opening this up in an incognito window, for example, 49 00:02:13,810 --> 00:02:17,910 taking the same URL, pasting it in, the other user 50 00:02:17,910 --> 00:02:21,910 is also going to see that they have two tasks, foo and bar. 51 00:02:21,910 --> 00:02:23,910 And if this other user here on the right creates 52 00:02:23,910 --> 00:02:27,810 a new task called baz and submits it, then the user on the left 53 00:02:27,810 --> 00:02:31,530 will also see the task baz if they are to refresh that page. 54 00:02:31,530 --> 00:02:35,250 And that's probably not what we want for some sort of application that 55 00:02:35,250 --> 00:02:39,000 allows users to maintain their own lists of tasks, for example. 56 00:02:39,000 --> 00:02:42,750 Ideally, I don't want the list of tasks to be a global variable. 57 00:02:42,750 --> 00:02:46,260 I wanted data to be data that is local to someone's session. 58 00:02:46,260 --> 00:02:48,722 That when I log in, I should see my tasks. 59 00:02:48,722 --> 00:02:50,430 And when I'm interacting with the page, I 60 00:02:50,430 --> 00:02:52,660 should be able to add to my list of tasks. 61 00:02:52,660 --> 00:02:56,490 But that shouldn't affect someone else who has their own list of tasks 62 00:02:56,490 --> 00:02:59,280 that they're maintaining on the same web application. 63 00:02:59,280 --> 00:03:02,910 So let's now see if we can implement this by introducing sessions 64 00:03:02,910 --> 00:03:04,387 into our web application. 65 00:03:04,387 --> 00:03:06,720 There are a couple of setup things that I'll need to do. 66 00:03:06,720 --> 00:03:10,080 From Flask, I'll need to import session, lowercase s. 67 00:03:10,080 --> 00:03:13,530 And I'm also going to use a library called Flask Session, where 68 00:03:13,530 --> 00:03:16,650 I'm going to import uppercase S Session, which will just give me access 69 00:03:16,650 --> 00:03:18,435 to some additional features. 70 00:03:18,435 --> 00:03:21,060 After here, there's some configuration steps that I need to do. 71 00:03:21,060 --> 00:03:23,352 No need to worry too much about the details about this. 72 00:03:23,352 --> 00:03:27,145 But in short, what I'm going to say is that session permanent 73 00:03:27,145 --> 00:03:28,020 is going to be false. 74 00:03:28,020 --> 00:03:29,850 I don't want sessions to be permanent. 75 00:03:29,850 --> 00:03:34,080 And then I'm going to add a session type equals file system 76 00:03:34,080 --> 00:03:37,350 to mean the location where I want to store all of the data pertaining 77 00:03:37,350 --> 00:03:41,190 to sessions is going to be any file system of the web server 78 00:03:41,190 --> 00:03:45,090 that I'm running this application from, which in this case is CS50 IDE. 79 00:03:45,090 --> 00:03:47,220 And then the final configuration step is just 80 00:03:47,220 --> 00:03:50,610 to say capital S session, in parentheses, app, 81 00:03:50,610 --> 00:03:54,660 to mean that I would like to enable sessions for this particular Flask web 82 00:03:54,660 --> 00:03:56,140 application. 83 00:03:56,140 --> 00:03:57,430 So what does this mean? 84 00:03:57,430 --> 00:04:01,020 What this means is that I'm now going to have access to a Python dictionary. 85 00:04:01,020 --> 00:04:04,650 Recalling that a data dictionary is just a collection of key value pairs 86 00:04:04,650 --> 00:04:07,830 called session where I can access information 87 00:04:07,830 --> 00:04:11,850 that is going to be local to the user's current interaction with the web page. 88 00:04:11,850 --> 00:04:15,030 And it's not going to be dependent upon what other users have also 89 00:04:15,030 --> 00:04:18,000 added to their own lists of tasks. 90 00:04:18,000 --> 00:04:20,850 What that means is that I can get rid of this list, which 91 00:04:20,850 --> 00:04:22,410 I'm going to call todos. 92 00:04:22,410 --> 00:04:25,350 And instead, inside of tasks, we're going 93 00:04:25,350 --> 00:04:28,720 to use a key within the session dictionary. 94 00:04:28,720 --> 00:04:31,590 So what I'm going to say inside of tasks is this first line. 95 00:04:31,590 --> 00:04:35,130 I'm going to check, is there already a key called-- 96 00:04:35,130 --> 00:04:38,540 we'll call it todos inside of the session. 97 00:04:38,540 --> 00:04:42,780 And in particular, if todos is not already in the session, 98 00:04:42,780 --> 00:04:44,860 well, then I want to add it to the session. 99 00:04:44,860 --> 00:04:50,010 So then I want to say session todos, it's just going to be the empty list. 100 00:04:50,010 --> 00:04:51,500 So what are these two lines doing? 101 00:04:51,500 --> 00:04:54,230 Well, these two lines are saying, for the current user, 102 00:04:54,230 --> 00:04:58,880 do they already have a key called todos inside the current user's session 103 00:04:58,880 --> 00:04:59,840 dictionary. 104 00:04:59,840 --> 00:05:04,250 If they don't, then we're going to create a new key inside of the session 105 00:05:04,250 --> 00:05:07,520 dictionary called todos them and set it equal to the empty list. 106 00:05:07,520 --> 00:05:11,420 Meaning initially, the user has no tasks that are currently inside 107 00:05:11,420 --> 00:05:13,220 of their list of tasks. 108 00:05:13,220 --> 00:05:14,570 All right, let's move on. 109 00:05:14,570 --> 00:05:18,290 Now in tasks.html, rather than passing in todos 110 00:05:18,290 --> 00:05:22,400 as just a variable todos, which was a global variable that we no longer have, 111 00:05:22,400 --> 00:05:25,580 now we're going to say the list of things to do is going to be 112 00:05:25,580 --> 00:05:29,120 session, square bracket, todos. 113 00:05:29,120 --> 00:05:32,390 In other words, for the current user session, the current user's interaction 114 00:05:32,390 --> 00:05:38,230 with this website, let's get at their list of things to do. 115 00:05:38,230 --> 00:05:41,870 So that's the function that's going to display the current list of tasks. 116 00:05:41,870 --> 00:05:44,320 But now let's go down here to the add function. 117 00:05:44,320 --> 00:05:46,190 What needs to change here? 118 00:05:46,190 --> 00:05:48,730 Well, we've gotten the current task, the thing to do, 119 00:05:48,730 --> 00:05:50,810 based on whatever was passed into that form. 120 00:05:50,810 --> 00:05:56,170 Request.form.get task means get whatever the user typed in to that task field. 121 00:05:56,170 --> 00:06:00,190 And now what we'd like to do is add it to the current users list of things 122 00:06:00,190 --> 00:06:01,560 that they need to do. 123 00:06:01,560 --> 00:06:05,710 So here we have todos.append todo, where before todos was 124 00:06:05,710 --> 00:06:08,230 a global variable, accessible by all users who 125 00:06:08,230 --> 00:06:10,270 were using this web application. 126 00:06:10,270 --> 00:06:13,820 But now what I'd like to do is make this local to the current user. 127 00:06:13,820 --> 00:06:16,480 And so the way I can do that is, instead of saying todos, 128 00:06:16,480 --> 00:06:21,550 I'll say session todos, to mean, take the current user session, 129 00:06:21,550 --> 00:06:25,390 access their list of things to do, and add to that list 130 00:06:25,390 --> 00:06:28,390 this new thing that I need to do. 131 00:06:28,390 --> 00:06:30,250 So instead of using a global variable, I'm 132 00:06:30,250 --> 00:06:33,180 now using part of the session dictionary in order 133 00:06:33,180 --> 00:06:37,380 to include and store data that is relevant to the current user only. 134 00:06:37,380 --> 00:06:38,550 Let's try this out. 135 00:06:38,550 --> 00:06:42,640 I'll run the web application by running Flask Run. 136 00:06:42,640 --> 00:06:45,950 And now if we take a look at the web application, loading it in both pages 137 00:06:45,950 --> 00:06:47,600 for two different users. 138 00:06:47,600 --> 00:06:51,740 Now if user number 1 creates a new task called foo and then creates 139 00:06:51,740 --> 00:06:55,040 a new task called bar, they still see their own tasks. 140 00:06:55,040 --> 00:06:59,000 But if user 2, if I refresh the page, they don't see those same tasks. 141 00:06:59,000 --> 00:07:01,970 User 2 can now create a new task, baz, for example. 142 00:07:01,970 --> 00:07:06,510 And now they have their own separate list of things that they need to do. 143 00:07:06,510 --> 00:07:09,260 Because this data is no longer being stored as a global variable. 144 00:07:09,260 --> 00:07:12,920 It's instead being stored in each user's individual session. 145 00:07:12,920 --> 00:07:15,860 And presumably Flask is asking the web browsers here 146 00:07:15,860 --> 00:07:19,280 to store some sort of cookie, some unique identifying information 147 00:07:19,280 --> 00:07:22,580 such that the next time you go to this page, that's by reloading the page, 148 00:07:22,580 --> 00:07:27,530 Flask still knows who the user is and can display that user's list of tasks 149 00:07:27,530 --> 00:07:30,770 back to them when they try and view this particular route on the web 150 00:07:30,770 --> 00:07:34,200 application. 151 00:07:34,200 --> 00:07:36,260 All right, so taking advantage of sessions, 152 00:07:36,260 --> 00:07:38,270 we now have the ability to store information 153 00:07:38,270 --> 00:07:40,760 that just pertains to the current user. 154 00:07:40,760 --> 00:07:43,670 But as we start to think about users interacting with our web page, 155 00:07:43,670 --> 00:07:45,530 you might imagine that our web applications are going 156 00:07:45,530 --> 00:07:47,107 to need to store more and more data. 157 00:07:47,107 --> 00:07:49,190 We're going to need to store data about the users, 158 00:07:49,190 --> 00:07:51,120 any information relevant to those users. 159 00:07:51,120 --> 00:07:53,885 And that's going to start to become a lot of information to store. 160 00:07:53,885 --> 00:07:55,760 And there are many ways you could store data. 161 00:07:55,760 --> 00:07:57,830 You could just always store data in the sessions. 162 00:07:57,830 --> 00:07:59,247 But the sessions aren't permanent. 163 00:07:59,247 --> 00:08:01,730 And so eventually you might lose that information. 164 00:08:01,730 --> 00:08:03,517 You could store data inside of a file. 165 00:08:03,517 --> 00:08:05,850 But then you need to know how to open and read that file 166 00:08:05,850 --> 00:08:07,400 and write to that file all the time. 167 00:08:07,400 --> 00:08:10,567 But this is a great opportunity to take advantage of something we've already 168 00:08:10,567 --> 00:08:14,480 taken a look at, which are databases, using a language like SQL that 169 00:08:14,480 --> 00:08:17,990 lets us interact with a SQLite database, for example, in order 170 00:08:17,990 --> 00:08:21,980 to have tables of data, to insert rows into that table of data, 171 00:08:21,980 --> 00:08:25,670 to update those rows, and to select rows out of that table such 172 00:08:25,670 --> 00:08:29,210 that we can write a web application that connects to a database 173 00:08:29,210 --> 00:08:31,730 and that uses the data inside of that database 174 00:08:31,730 --> 00:08:35,515 to display information to people that are using the web application. 175 00:08:35,515 --> 00:08:36,890 And so that's what we'll do next. 176 00:08:36,890 --> 00:08:39,020 Create a new web application that we'll just say 177 00:08:39,020 --> 00:08:41,539 is going to allow people to register for something, 178 00:08:41,539 --> 00:08:45,140 be it registering for a mailing list or registering for a club 179 00:08:45,140 --> 00:08:47,187 or registering for something else. 180 00:08:47,187 --> 00:08:50,270 You can think of this as an application that's going to store information. 181 00:08:50,270 --> 00:08:52,270 And the information we're going to need to store 182 00:08:52,270 --> 00:08:55,610 is data about all of the registrants for the event or for the club 183 00:08:55,610 --> 00:08:57,920 or whatever it is that people are registering for. 184 00:08:57,920 --> 00:09:00,800 And what sort of information might we want to store? 185 00:09:00,800 --> 00:09:03,920 Well, we probably want to store for each registrant their name 186 00:09:03,920 --> 00:09:06,480 and maybe their email address as well. 187 00:09:06,480 --> 00:09:07,760 And so let's give this a try. 188 00:09:07,760 --> 00:09:10,180 I'll go back into CS50 IDE. 189 00:09:10,180 --> 00:09:14,875 And now, let's go ahead and create a new directory for a new application 190 00:09:14,875 --> 00:09:16,250 that we're going to create. 191 00:09:16,250 --> 00:09:18,710 We'll call the application register. 192 00:09:18,710 --> 00:09:20,900 And I'll create a new file. 193 00:09:20,900 --> 00:09:24,800 And this new file that I'm going to create is going to be a database file. 194 00:09:24,800 --> 00:09:26,600 I'll call it lecture.db. 195 00:09:26,600 --> 00:09:30,290 So just create an empty SQLite database. 196 00:09:30,290 --> 00:09:34,130 Now I'll go ahead and cd into register. 197 00:09:34,130 --> 00:09:37,550 And now in order to access this database, lecture.db, 198 00:09:37,550 --> 00:09:42,050 I'll run SQLite3 lecture.db. 199 00:09:42,050 --> 00:09:44,090 And so this now takes me into SQLite where 200 00:09:44,090 --> 00:09:47,840 I can run SQL queries on this particular database. 201 00:09:47,840 --> 00:09:49,470 And so what am I going to do? 202 00:09:49,470 --> 00:09:53,150 Well, the first thing I need to do inside this database is create a table. 203 00:09:53,150 --> 00:09:55,100 So I'll go ahead and run some syntax. 204 00:09:55,100 --> 00:09:56,720 So I'll say create table. 205 00:09:56,720 --> 00:09:59,700 We'll call the table registrants. 206 00:09:59,700 --> 00:10:03,890 And what are the columns that this table needs to have? 207 00:10:03,890 --> 00:10:06,890 Well, presumably, like many tables, it should have an ID column 208 00:10:06,890 --> 00:10:09,150 that will uniquely identify users. 209 00:10:09,150 --> 00:10:11,300 So the ID column will be an integer. 210 00:10:11,300 --> 00:10:13,530 And we'll say that it will be the primary key. 211 00:10:13,530 --> 00:10:14,300 It will be unique. 212 00:10:14,300 --> 00:10:19,130 It'll be the way that we identify every single registrant inside of this table. 213 00:10:19,130 --> 00:10:22,410 And let's also add now a field for their name. 214 00:10:22,410 --> 00:10:24,860 Their name is presumably going to have some sort of type. 215 00:10:24,860 --> 00:10:27,440 And recall that we can use varchar as the name 216 00:10:27,440 --> 00:10:31,400 of a type of a column that store some variable number of characters. 217 00:10:31,400 --> 00:10:34,310 And we'll say we'll store up to 255 characters, which 218 00:10:34,310 --> 00:10:36,890 feels like a pretty reasonable limit for a name. 219 00:10:36,890 --> 00:10:40,580 And then we'll also store an email address column, which 220 00:10:40,580 --> 00:10:43,900 we'll also specify as varchar 255. 221 00:10:43,900 --> 00:10:48,990 And so we've now created a table that has three columns-- 222 00:10:48,990 --> 00:10:52,500 an ID column, which is an integer, a name column, which 223 00:10:52,500 --> 00:10:55,950 is a variable number of characters, and an email column, which is also 224 00:10:55,950 --> 00:10:57,620 a variable number of characters. 225 00:10:57,620 --> 00:11:00,780 And here in the SQLite terminal, we can actually try and select this data. 226 00:11:00,780 --> 00:11:04,332 I can say, select star from registrants. 227 00:11:04,332 --> 00:11:06,540 And of course nothing happens because right now there 228 00:11:06,540 --> 00:11:09,420 is no data inside of this registrants table. 229 00:11:09,420 --> 00:11:11,400 But let's add some data. 230 00:11:11,400 --> 00:11:17,490 I'll insert into registrants a name and an email address. 231 00:11:17,490 --> 00:11:19,380 And what values do I want to insert? 232 00:11:19,380 --> 00:11:22,860 Well, let's use the name of Alice, for example, 233 00:11:22,860 --> 00:11:25,260 and an email address of alice@example.com. 234 00:11:25,260 --> 00:11:29,070 235 00:11:29,070 --> 00:11:33,150 So I've run a SQL query to insert into the registrants table a new row. 236 00:11:33,150 --> 00:11:35,220 I've inserted a row with a name and an email 237 00:11:35,220 --> 00:11:37,530 with the values of Alice and alice@example.com. 238 00:11:37,530 --> 00:11:41,940 And now if I go back and select star from registrants, 239 00:11:41,940 --> 00:11:45,540 selecting all of the data from that table, we'll say, 240 00:11:45,540 --> 00:11:48,420 we have Alice who's automatically given an ID of 1, who has 241 00:11:48,420 --> 00:11:52,770 an email address of alice@example.com. 242 00:11:52,770 --> 00:11:54,960 So now that we've created this database file, 243 00:11:54,960 --> 00:11:58,530 lecture.db, which is a SQLite database inside of which 244 00:11:58,530 --> 00:12:02,280 is a table called registrants, let's now create a web application that's 245 00:12:02,280 --> 00:12:05,760 able to actually use that database to read and write data to it 246 00:12:05,760 --> 00:12:09,450 in order to display those registrants and update the list of registrants 247 00:12:09,450 --> 00:12:12,970 if someone new registers using our web application. 248 00:12:12,970 --> 00:12:15,340 So this is going to be a Flask web application. 249 00:12:15,340 --> 00:12:17,687 So the first thing we'll do is create a new file. 250 00:12:17,687 --> 00:12:19,020 And I'll call it application.py. 251 00:12:19,020 --> 00:12:24,510 And again, this is where the Flask application is going to be stored. 252 00:12:24,510 --> 00:12:27,160 From Flask, import Flask-- same as before. 253 00:12:27,160 --> 00:12:31,800 This time, though, I'm also going to add from CS50. 254 00:12:31,800 --> 00:12:36,030 Let's import SQL because I want to use CS50's SQL library, because I 255 00:12:36,030 --> 00:12:38,580 want my Flask application to now have the ability 256 00:12:38,580 --> 00:12:41,860 to interact with the database that I'm about to create. 257 00:12:41,860 --> 00:12:46,600 So beneath that we'll say app equals Flask name, same as before. 258 00:12:46,600 --> 00:12:49,470 And now I want to give my web application access to this database, 259 00:12:49,470 --> 00:12:50,910 lecture.db. 260 00:12:50,910 --> 00:12:57,280 So I'm going to say db, for database, equals, and then SQL, and then SQLite, 261 00:12:57,280 --> 00:13:03,270 :///, three slashes, specifying that this is going to be a SQLite database. 262 00:13:03,270 --> 00:13:05,760 And then what is the name of the database file? 263 00:13:05,760 --> 00:13:09,420 Well, the name of the database file is lecture.db. 264 00:13:09,420 --> 00:13:14,550 And now db is going to give me access to lecture.db. 265 00:13:14,550 --> 00:13:16,590 And it's going to allow me to run SQL queries, 266 00:13:16,590 --> 00:13:20,190 be they selects or inserts or updates, that then are able to get at data 267 00:13:20,190 --> 00:13:24,750 and modify data inside of the lecture.db database. 268 00:13:24,750 --> 00:13:25,900 Next, let's create a route. 269 00:13:25,900 --> 00:13:28,890 I'll create app.route/. 270 00:13:28,890 --> 00:13:30,460 We'll call the route index. 271 00:13:30,460 --> 00:13:34,530 And what I'd like for the route to do is just display to me all of the people 272 00:13:34,530 --> 00:13:39,100 that are currently registered, based on the data inside of my database. 273 00:13:39,100 --> 00:13:40,510 How might I go about doing that? 274 00:13:40,510 --> 00:13:42,218 Well, in order to get the data, I'm going 275 00:13:42,218 --> 00:13:44,910 to need to run a query on the SQL database. 276 00:13:44,910 --> 00:13:48,270 To do that, I can run db.execute. 277 00:13:48,270 --> 00:13:50,190 And then in parentheses and quotation marks, 278 00:13:50,190 --> 00:13:52,950 the name of the query that I now want to run. 279 00:13:52,950 --> 00:13:57,660 In this case, it'll be select star from registrants, 280 00:13:57,660 --> 00:14:02,190 because I'd like to select all of the data from the registrants table. 281 00:14:02,190 --> 00:14:04,980 When I select all that data, the data is going to come back to me. 282 00:14:04,980 --> 00:14:08,130 And I'm going to want to store that data inside of a variable, which 283 00:14:08,130 --> 00:14:10,110 we'll call rows, in this case. 284 00:14:10,110 --> 00:14:13,560 So I'm making a query on the database, running select start from registrants, 285 00:14:13,560 --> 00:14:17,400 which is a SQL query, taking the result, and saving it inside 286 00:14:17,400 --> 00:14:20,280 of this Python variable called rows. 287 00:14:20,280 --> 00:14:21,610 What do I do now? 288 00:14:21,610 --> 00:14:25,320 Well, now I'd like to take this variable rows and pass it into a template 289 00:14:25,320 --> 00:14:29,040 so that I can render the information about who is currently registered. 290 00:14:29,040 --> 00:14:30,580 Let's try that. 291 00:14:30,580 --> 00:14:34,020 So I'll say return render template. 292 00:14:34,020 --> 00:14:37,020 We'll call the template index.html, which doesn't yet exist, 293 00:14:37,020 --> 00:14:38,650 but we'll create it in just a moment. 294 00:14:38,650 --> 00:14:43,680 And say that index.html is going to have access to a variable called rows, which 295 00:14:43,680 --> 00:14:48,150 will be equal to rows, the result of whatever came back from the SQL query 296 00:14:48,150 --> 00:14:50,770 that we ran on line 10. 297 00:14:50,770 --> 00:14:55,460 I'll also need to import render template in order to make this work. 298 00:14:55,460 --> 00:15:00,500 But let's now create a new folder called templates inside of which we'll 299 00:15:00,500 --> 00:15:03,730 create a new file called index.html. 300 00:15:03,730 --> 00:15:06,980 And index.html will be the template that we're going to render. 301 00:15:06,980 --> 00:15:12,590 So DOCTYPE HTML, HTML, head. 302 00:15:12,590 --> 00:15:16,290 We'll go ahead and give this a title and call it registrants. 303 00:15:16,290 --> 00:15:18,230 And inside the body of the page now, I'll 304 00:15:18,230 --> 00:15:21,320 make a big heading at the top that just says registrants. 305 00:15:21,320 --> 00:15:24,140 But now what I'd like is a list of all of the people 306 00:15:24,140 --> 00:15:27,200 that are currently registered according to my database. 307 00:15:27,200 --> 00:15:28,680 How am I going to do that? 308 00:15:28,680 --> 00:15:32,770 Well, recall that UL can be used to create an unordered list. 309 00:15:32,770 --> 00:15:35,240 And inside of that UL, I'd like to loop over 310 00:15:35,240 --> 00:15:39,930 all of the rows that got passed into my index.html template. 311 00:15:39,930 --> 00:15:44,830 So I'll say, for row in rows, and then endfor. 312 00:15:44,830 --> 00:15:47,510 Recalling that this syntax, a curly brace percent sign, 313 00:15:47,510 --> 00:15:49,730 is how I can add a loop into my template. 314 00:15:49,730 --> 00:15:53,810 Say loop over all of the rows that got passed into index.html. 315 00:15:53,810 --> 00:15:57,470 And for each one of those rows, what HTML do I want to add? 316 00:15:57,470 --> 00:16:02,120 Well, I want to add an LI, a list item, that's going to show up in this list. 317 00:16:02,120 --> 00:16:05,930 And I'd like to here plug in the name and the email address 318 00:16:05,930 --> 00:16:07,950 of every person who's registered. 319 00:16:07,950 --> 00:16:10,340 And so every row that comes back to me is 320 00:16:10,340 --> 00:16:12,800 going to be in the format of a Python dictionary, 321 00:16:12,800 --> 00:16:15,930 where the keys are going to be the names of all of the columns-- 322 00:16:15,930 --> 00:16:17,900 ID, name, and email. 323 00:16:17,900 --> 00:16:20,270 And I can access the values that those keys 324 00:16:20,270 --> 00:16:24,650 to get at the person's name and the person's email address, for example. 325 00:16:24,650 --> 00:16:28,760 And so rows with all of the rows that came back from my registrants table, 326 00:16:28,760 --> 00:16:33,270 each individual row is just one row that comes back from my registrants table. 327 00:16:33,270 --> 00:16:36,680 And if I want the name that corresponds with that row, 328 00:16:36,680 --> 00:16:40,460 well, I'm going to print out as by using double curly braces to substitute 329 00:16:40,460 --> 00:16:42,680 a value here into the template-- 330 00:16:42,680 --> 00:16:46,220 row, and then in square brackets, name. 331 00:16:46,220 --> 00:16:49,820 Say take the current row, get at the person's name, and plug in that value 332 00:16:49,820 --> 00:16:50,840 here. 333 00:16:50,840 --> 00:16:53,300 I may also want to include their email address, which I'll 334 00:16:53,300 --> 00:16:56,040 do in parentheses for good measure. 335 00:16:56,040 --> 00:16:58,070 And then I'll add another set of curly braces 336 00:16:58,070 --> 00:17:03,510 and go ahead and substitute in row, square bracket, email as well. 337 00:17:03,510 --> 00:17:06,859 So now I'm showing a list item for every row in my table, 338 00:17:06,859 --> 00:17:12,390 where I'm saying the row name, and then the row email. 339 00:17:12,390 --> 00:17:15,430 Let's now try to run this web application. 340 00:17:15,430 --> 00:17:20,200 I'll go down into the terminal and run Flask Run to run the application. 341 00:17:20,200 --> 00:17:24,280 And now if I try and load the page, I now see registrants. 342 00:17:24,280 --> 00:17:25,390 And now I see a list-- 343 00:17:25,390 --> 00:17:29,050 Alice, and then alice@example.com as the email address 344 00:17:29,050 --> 00:17:31,302 of the person who's registered. 345 00:17:31,302 --> 00:17:33,260 And so if we ever were to update this database, 346 00:17:33,260 --> 00:17:36,680 changing the data inside the database, this list would also update. 347 00:17:36,680 --> 00:17:38,990 And we can see that if we go back here. 348 00:17:38,990 --> 00:17:43,640 I'll go ahead and type in SQLite3 lecture.db to go back to the database. 349 00:17:43,640 --> 00:17:47,780 And let me insert into registrants a new name and email. 350 00:17:47,780 --> 00:17:49,720 This time, what values am I going to insert? 351 00:17:49,720 --> 00:17:52,700 We'll add Bob and then bob@example.com. 352 00:17:52,700 --> 00:17:59,740 And now if I exit out of the database and run Flask Run, 353 00:17:59,740 --> 00:18:03,020 and I reload this web page, well, now I have two registrants. 354 00:18:03,020 --> 00:18:06,460 I have Alice and I have Bob. 355 00:18:06,460 --> 00:18:09,190 So now we have the ability to design a web application that's 356 00:18:09,190 --> 00:18:11,480 able to read data from a database. 357 00:18:11,480 --> 00:18:12,880 We have a SQLite database. 358 00:18:12,880 --> 00:18:15,940 And our route now is reading data from that database 359 00:18:15,940 --> 00:18:19,750 and displaying the information in the database in the form of an HTML list 360 00:18:19,750 --> 00:18:20,600 here. 361 00:18:20,600 --> 00:18:23,770 Let's now add to this and actually build into our web application 362 00:18:23,770 --> 00:18:26,530 the ability to register as well, the ability 363 00:18:26,530 --> 00:18:31,540 to add data to the registrants table instead of just reading data from it. 364 00:18:31,540 --> 00:18:33,010 Let's give that a try. 365 00:18:33,010 --> 00:18:35,710 Inside of index.html, we'll go ahead and add a link 366 00:18:35,710 --> 00:18:38,230 at the bottom that will give me a way to register. 367 00:18:38,230 --> 00:18:41,780 It will be a link that'll take me to /register, for example, 368 00:18:41,780 --> 00:18:44,890 which is a route that doesn't yet exist, but we'll create it. 369 00:18:44,890 --> 00:18:49,490 And the link will just say register. 370 00:18:49,490 --> 00:18:51,620 What should this route do? 371 00:18:51,620 --> 00:18:54,670 Here's app.route/register. 372 00:18:54,670 --> 00:18:58,380 We'll create a function called register. 373 00:18:58,380 --> 00:19:04,950 And for now, let's just go ahead and render a template, register.html. 374 00:19:04,950 --> 00:19:07,826 Let's now create register.html. 375 00:19:07,826 --> 00:19:11,498 So I'll create a new file, call it register.html, 376 00:19:11,498 --> 00:19:14,540 which for now is going to include the same information that was currently 377 00:19:14,540 --> 00:19:15,950 in index.html. 378 00:19:15,950 --> 00:19:19,280 And I could improve the design of this somewhat by factoring out information 379 00:19:19,280 --> 00:19:22,650 into a layout.html file, the way I have previously as well. 380 00:19:22,650 --> 00:19:24,410 So definitely something to consider too. 381 00:19:24,410 --> 00:19:26,420 But here for now, what I really want to do 382 00:19:26,420 --> 00:19:30,530 is inside of the body I'll call the title register. 383 00:19:30,530 --> 00:19:34,960 And here I'd like to create a form, a form that has an input, whose 384 00:19:34,960 --> 00:19:38,410 type is text, and whose name is name. 385 00:19:38,410 --> 00:19:40,150 I want the person to type in their name. 386 00:19:40,150 --> 00:19:45,260 And so that they know that, I'll add a placeholder that says name. 387 00:19:45,260 --> 00:19:50,510 And I'll also have an input whose type is text and whose name is email. 388 00:19:50,510 --> 00:19:54,080 And just so the user knows that, I'll add a placeholder for the input field 389 00:19:54,080 --> 00:19:56,150 that says email address. 390 00:19:56,150 --> 00:19:59,330 And then I'll have an input whose type is 391 00:19:59,330 --> 00:20:04,580 submit, which will give the user the ability 392 00:20:04,580 --> 00:20:07,460 to submit this form after they've typed in their name 393 00:20:07,460 --> 00:20:10,520 and typed in their email address. 394 00:20:10,520 --> 00:20:12,255 What would I like this form to do? 395 00:20:12,255 --> 00:20:15,120 Well, the form's action, when you submit the form, 396 00:20:15,120 --> 00:20:17,930 we'll go ahead and also go to the /register route. 397 00:20:17,930 --> 00:20:19,580 But again, I'm submitting data. 398 00:20:19,580 --> 00:20:24,410 And so oftentimes when I'm doing this, I want to add a request method of post 399 00:20:24,410 --> 00:20:30,790 to say that I would like to submit data via post to my /register route. 400 00:20:30,790 --> 00:20:35,150 So what does that mean we need to do with our /register route here inside 401 00:20:35,150 --> 00:20:36,490 of application.py? 402 00:20:36,490 --> 00:20:38,240 Well, first and foremost, it means we need 403 00:20:38,240 --> 00:20:40,520 to accept multiple requests methods. 404 00:20:40,520 --> 00:20:43,430 We need to not just allow for get requests, 405 00:20:43,430 --> 00:20:48,200 but also allow for post requests to be made to /register as well. 406 00:20:48,200 --> 00:20:55,850 If the request method is get, then we're going to return register.html. 407 00:20:55,850 --> 00:20:58,600 And I'll go ahead an import request up here as well so 408 00:20:58,600 --> 00:21:01,650 that we have access to the request. 409 00:21:01,650 --> 00:21:04,560 Otherwise, though, else, if the request method is post, 410 00:21:04,560 --> 00:21:07,740 that means the user has tried to submit this form. 411 00:21:07,740 --> 00:21:09,090 So what am I going to do? 412 00:21:09,090 --> 00:21:13,620 Well, I'll say name equals request.form.get name, 413 00:21:13,620 --> 00:21:17,430 and email equals request.form.get email. 414 00:21:17,430 --> 00:21:20,100 In other words, if the user submits this form via post, 415 00:21:20,100 --> 00:21:23,550 then I want to look at the information that was submitted inside of that form 416 00:21:23,550 --> 00:21:27,060 and access the user's name and the user's email address, 417 00:21:27,060 --> 00:21:30,660 storing them in these values, name and email. 418 00:21:30,660 --> 00:21:33,430 Then what would I like to do with that information? 419 00:21:33,430 --> 00:21:35,760 Well, I'm going to run a query that is going 420 00:21:35,760 --> 00:21:39,870 to insert this data into the database to indicate that this user is now 421 00:21:39,870 --> 00:21:41,160 registered. 422 00:21:41,160 --> 00:21:42,670 But what does that query look like? 423 00:21:42,670 --> 00:21:45,163 Well, it'll be db.execute. 424 00:21:45,163 --> 00:21:46,830 And then what's the query for inserting? 425 00:21:46,830 --> 00:21:50,220 It'll be insert into registrants. 426 00:21:50,220 --> 00:21:51,750 What columns am I going to add? 427 00:21:51,750 --> 00:21:56,550 Well, I'm going to add a name and an email, and then values. 428 00:21:56,550 --> 00:22:00,163 And then what I'd like to do is provide a name and an email here. 429 00:22:00,163 --> 00:22:02,580 Now you could try and do some sort of string concatenation 430 00:22:02,580 --> 00:22:04,970 to try and plug in the value of the variable name 431 00:22:04,970 --> 00:22:06,510 and the value the variable email. 432 00:22:06,510 --> 00:22:09,635 But you have to be careful about that because you potentially open yourself 433 00:22:09,635 --> 00:22:11,940 up to SQL injection attacks if you're literally 434 00:22:11,940 --> 00:22:14,340 including strings inside of the query. 435 00:22:14,340 --> 00:22:16,650 Whoever called it a SQL injection attack is 436 00:22:16,650 --> 00:22:21,840 where if name or email happens to include some SQL-looking syntax, then 437 00:22:21,840 --> 00:22:24,690 you might end up executing some dangerous SQL code 438 00:22:24,690 --> 00:22:26,230 inside of your database. 439 00:22:26,230 --> 00:22:31,770 So just to be safe, we're going to use placeholders here by saying :name 440 00:22:31,770 --> 00:22:35,490 and :email to say we're going to plug in some name here, 441 00:22:35,490 --> 00:22:38,370 and we're going to plug in some value of an email here. 442 00:22:38,370 --> 00:22:40,260 And what values are we going to plug in? 443 00:22:40,260 --> 00:22:43,380 Well, we're going to plug in a value for name, which is just going 444 00:22:43,380 --> 00:22:46,110 to be equal to name, the variable name. 445 00:22:46,110 --> 00:22:48,165 And for the value email, we're going to plug 446 00:22:48,165 --> 00:22:50,830 in the value of the variable email. 447 00:22:50,830 --> 00:22:54,330 So again here, we're just defining these placeholders called name and email, 448 00:22:54,330 --> 00:22:56,760 where we're saying the value of the name placeholder, 449 00:22:56,760 --> 00:23:00,600 we should substitute with whatever the variable name is equal to. 450 00:23:00,600 --> 00:23:02,110 And same thing for email. 451 00:23:02,110 --> 00:23:05,230 In this case they just happen to have the same names. 452 00:23:05,230 --> 00:23:10,530 So I've inserted into the registrants table a new pair of name and email. 453 00:23:10,530 --> 00:23:14,730 And the last thing I'll do is I'll go ahead and redirect the user back 454 00:23:14,730 --> 00:23:19,200 to the /route, that default route that determines what should be shown, 455 00:23:19,200 --> 00:23:22,270 which is all of the lists of all the current registrants. 456 00:23:22,270 --> 00:23:26,400 Up at the top, to make this work, I'll go ahead and import redirect as well, 457 00:23:26,400 --> 00:23:30,990 since I want to be able to redirect the user after this happens. 458 00:23:30,990 --> 00:23:32,910 Let's give this web application a try. 459 00:23:32,910 --> 00:23:35,980 I'll run Flask Run. 460 00:23:35,980 --> 00:23:37,190 And now I'll reload the page. 461 00:23:37,190 --> 00:23:41,050 462 00:23:41,050 --> 00:23:44,270 And when the page reloads, I now see that Alice and Bob are still 463 00:23:44,270 --> 00:23:44,780 registered. 464 00:23:44,780 --> 00:23:46,430 They're still inside the database. 465 00:23:46,430 --> 00:23:50,000 But I now see this additional link Register at the bottom. 466 00:23:50,000 --> 00:23:53,960 When I click the Register link, I'm taken to the /register route on this 467 00:23:53,960 --> 00:23:56,690 web application where I'm now presented with a form, 468 00:23:56,690 --> 00:24:00,670 somewhere where I can type in a name and an email address, and then submit. 469 00:24:00,670 --> 00:24:04,430 And the placeholders that I included as attributes of these input fields 470 00:24:04,430 --> 00:24:06,590 are now showing up to me so that I know whether I 471 00:24:06,590 --> 00:24:10,410 should type in my name or the email address into which of these two fields. 472 00:24:10,410 --> 00:24:14,890 So we'll go ahead and type in Charlie and then charlie@example.com. 473 00:24:14,890 --> 00:24:17,000 And I'll click Submit. 474 00:24:17,000 --> 00:24:20,300 And OK, I get redirected back to the Registrants page. 475 00:24:20,300 --> 00:24:23,210 And now Charlie is a registrant as well. 476 00:24:23,210 --> 00:24:25,520 And I can confirm this if I go back, close out 477 00:24:25,520 --> 00:24:29,510 of the application, and type SQLite lecture.db 478 00:24:29,510 --> 00:24:32,750 and select star from registrants. 479 00:24:32,750 --> 00:24:34,280 I now have three registrants. 480 00:24:34,280 --> 00:24:36,072 You can't see Charlie's full email address. 481 00:24:36,072 --> 00:24:39,980 But we do see that we have Alice, Bob, and Charlie all inside 482 00:24:39,980 --> 00:24:42,320 of this registrants table. 483 00:24:42,320 --> 00:24:45,418 Let's put a few finishing touches on this web application. 484 00:24:45,418 --> 00:24:47,210 First and foremost, as we mentioned before, 485 00:24:47,210 --> 00:24:51,110 there was some overlap between index.html and register.html. 486 00:24:51,110 --> 00:24:54,920 So I'll first create a new file called layout.html, 487 00:24:54,920 --> 00:24:56,720 which will contain all of the HTML that's 488 00:24:56,720 --> 00:24:59,150 in common between the two HTML files. 489 00:24:59,150 --> 00:25:02,750 So I'll take register.html, paste it in here for now. 490 00:25:02,750 --> 00:25:06,020 And really the only thing that's going to differ between the two pages 491 00:25:06,020 --> 00:25:08,960 is the contents of block body. 492 00:25:08,960 --> 00:25:13,310 So I'll create a body block we're now inside of index.html, 493 00:25:13,310 --> 00:25:18,450 instead of all of this, I can just say we're going to extend layout.html. 494 00:25:18,450 --> 00:25:22,470 And then inside of block body is going to be the list 495 00:25:22,470 --> 00:25:24,270 of all the current registrants. 496 00:25:24,270 --> 00:25:28,910 And then I'll end the block after that. 497 00:25:28,910 --> 00:25:31,200 So, simplifying the code just a little bit. 498 00:25:31,200 --> 00:25:34,940 And I'll do the same thing in register.html where instead of all this 499 00:25:34,940 --> 00:25:38,930 I'll just say we're going to extend layout.html. 500 00:25:38,930 --> 00:25:42,140 And inside of block body, we have register up at the top, 501 00:25:42,140 --> 00:25:45,105 and then the form where the user can actually register here too. 502 00:25:45,105 --> 00:25:48,230 So this shouldn't actually change the way the application behaves, but just 503 00:25:48,230 --> 00:25:49,760 cleans up the code a little bit. 504 00:25:49,760 --> 00:25:52,040 In case we want to make modifications to the layout, 505 00:25:52,040 --> 00:25:55,210 it will affect all of the different HTML pages. 506 00:25:55,210 --> 00:25:58,390 But let's now actually do some changing of the logic of our application. 507 00:25:58,390 --> 00:26:00,140 Because one thing we haven't yet accounted 508 00:26:00,140 --> 00:26:03,800 for is the possibility that maybe the user didn't type in their name 509 00:26:03,800 --> 00:26:06,030 correctly or didn't type in an email correctly. 510 00:26:06,030 --> 00:26:08,900 And one of these two fields is blank, for example. 511 00:26:08,900 --> 00:26:10,440 What might we do then? 512 00:26:10,440 --> 00:26:13,880 Well, let's create an apology.html page, which will just 513 00:26:13,880 --> 00:26:17,060 be an error page where we apologize to the user 514 00:26:17,060 --> 00:26:20,120 if we can't perform the requested action for some reason. 515 00:26:20,120 --> 00:26:23,360 So I'll go ahead in templates and create a new file, which 516 00:26:23,360 --> 00:26:31,310 I'll call apology.html, inside of which we'll go ahead and extend layout.html 517 00:26:31,310 --> 00:26:32,840 again. 518 00:26:32,840 --> 00:26:36,480 And then inside of block body, I'll display 519 00:26:36,480 --> 00:26:39,210 in each one that just says sorry. 520 00:26:39,210 --> 00:26:42,420 And then maybe we have some error message of something that happens. 521 00:26:42,420 --> 00:26:47,280 So inside of a div I'll display the value of a variable called 522 00:26:47,280 --> 00:26:49,055 message, which I haven't yet defined. 523 00:26:49,055 --> 00:26:50,640 But we'll get there in a moment. 524 00:26:50,640 --> 00:26:55,350 And then at the bottom, maybe a link that takes me back home that just says 525 00:26:55,350 --> 00:26:56,710 go back. 526 00:26:56,710 --> 00:26:58,530 So this is an error message page, something 527 00:26:58,530 --> 00:27:01,800 that we're going to display if something goes wrong in the web application, 528 00:27:01,800 --> 00:27:02,980 for example. 529 00:27:02,980 --> 00:27:05,110 And when might something go wrong? 530 00:27:05,110 --> 00:27:08,550 Well, inside of application.py we might find that maybe the user 531 00:27:08,550 --> 00:27:10,140 didn't type in a name. 532 00:27:10,140 --> 00:27:13,230 So I can say, all right, if not name-- 533 00:27:13,230 --> 00:27:15,420 in other words, if no name was provided-- 534 00:27:15,420 --> 00:27:21,450 then what I want to do is return, render template, apology.html, 535 00:27:21,450 --> 00:27:27,710 passing in a message of, you must provide a name. 536 00:27:27,710 --> 00:27:31,940 And likewise, we can also add another condition that says, if not email-- 537 00:27:31,940 --> 00:27:34,280 if the user doesn't type in an email address-- 538 00:27:34,280 --> 00:27:38,760 then we should also return the template, apology.html, 539 00:27:38,760 --> 00:27:42,080 meaning some error took place, with a message of you 540 00:27:42,080 --> 00:27:44,290 must provide an email address. 541 00:27:44,290 --> 00:27:46,890 542 00:27:46,890 --> 00:27:48,377 Let's give this a try now. 543 00:27:48,377 --> 00:27:49,710 I'll go ahead and run Flask Run. 544 00:27:49,710 --> 00:27:53,200 545 00:27:53,200 --> 00:27:55,250 I'll load the web page. 546 00:27:55,250 --> 00:27:57,050 And I see my list of registrants. 547 00:27:57,050 --> 00:27:58,850 And now let me try to register. 548 00:27:58,850 --> 00:28:03,040 But let me leave both the name and the email address fields blank. 549 00:28:03,040 --> 00:28:04,820 I'll press Submit. 550 00:28:04,820 --> 00:28:08,010 And we get a sorry message that says, you must provide a name. 551 00:28:08,010 --> 00:28:08,650 Let's go back. 552 00:28:08,650 --> 00:28:10,108 We're taking back to the home page. 553 00:28:10,108 --> 00:28:11,123 I'll try register again. 554 00:28:11,123 --> 00:28:12,040 Let me type in a name. 555 00:28:12,040 --> 00:28:13,260 I'll type in Dave. 556 00:28:13,260 --> 00:28:14,760 Press Submit. 557 00:28:14,760 --> 00:28:16,690 Sorry, you must provide an email address. 558 00:28:16,690 --> 00:28:18,710 All right, let's go back. 559 00:28:18,710 --> 00:28:19,290 Register. 560 00:28:19,290 --> 00:28:20,040 I'll type in Dave. 561 00:28:20,040 --> 00:28:22,884 I'll type in dave@example.com. 562 00:28:22,884 --> 00:28:25,110 I'll press Submit. 563 00:28:25,110 --> 00:28:27,920 And now Dave was successfully registered as well. 564 00:28:27,920 --> 00:28:30,550 And I have this list of all four registrants 565 00:28:30,550 --> 00:28:32,950 that are currently inside of my SQLite database 566 00:28:32,950 --> 00:28:36,820 that I am reading from in order to display them all as individual list 567 00:28:36,820 --> 00:28:40,750 items inside of my HTML template. 568 00:28:40,750 --> 00:28:44,440 So by including SQL queries inside of our web applications, 569 00:28:44,440 --> 00:28:47,290 we now have the ability to write Flask applications that 570 00:28:47,290 --> 00:28:48,640 interact with a database. 571 00:28:48,640 --> 00:28:51,010 That are able to store data inside of a database 572 00:28:51,010 --> 00:28:53,230 and read data from that database in order 573 00:28:53,230 --> 00:28:57,070 to display that information dynamically to users who are visiting our page. 574 00:28:57,070 --> 00:29:01,000 And this really opens the door for a wide variety of possible applications 575 00:29:01,000 --> 00:29:02,080 that we can design. 576 00:29:02,080 --> 00:29:04,150 Any application that has multiple routes, 577 00:29:04,150 --> 00:29:06,070 that store in some sort of data, and that's 578 00:29:06,070 --> 00:29:09,670 using that data to be presented in templates, you can create just 579 00:29:09,670 --> 00:29:13,060 by combining these ideas, using HTML for the templates, 580 00:29:13,060 --> 00:29:15,940 using Flask as the web server that's listening for requests 581 00:29:15,940 --> 00:29:18,760 in particular routes, and responding with information, 582 00:29:18,760 --> 00:29:21,340 and by using a database like a SQLite database 583 00:29:21,340 --> 00:29:25,540 in order to store information that your web application needs access to. 584 00:29:25,540 --> 00:29:28,500 This, with web programming. 585 00:29:28,500 --> 00:29:29,000