WEBVTT 1 00:00:00.150 --> 00:00:02.100 Hi and welcome back. 2 00:00:02.100 --> 00:00:02.933 In this video, 3 00:00:02.933 --> 00:00:05.850 we're going to be creating our first HTML form, 4 00:00:05.850 --> 00:00:07.230 which is going to allow our users 5 00:00:07.230 --> 00:00:11.810 to create new posts in our in-memory database. 6 00:00:12.830 --> 00:00:14.340 In order to do that, we're going to create 7 00:00:14.340 --> 00:00:17.410 two new Flask endpoints. 8 00:00:17.410 --> 00:00:19.270 Let's go over down here, and create the first one, 9 00:00:19.270 --> 00:00:21.320 which is going to be very simple. 10 00:00:21.320 --> 00:00:25.720 It's going to give the users the form that they can fill in. 11 00:00:25.720 --> 00:00:30.150 So we're gonna do app.route /post/form. 12 00:00:30.150 --> 00:00:32.170 And then here we're gonna define a function 13 00:00:32.170 --> 00:00:35.970 that is going to return render template of create.jinja2. 14 00:00:36.860 --> 00:00:39.800 This is gonna be a file that we're gonna give our users 15 00:00:39.800 --> 00:00:43.050 which is going to contain the fields that they can fill in 16 00:00:43.050 --> 00:00:45.410 in order to create a new post. 17 00:00:45.410 --> 00:00:46.760 Let's go and do this first. 18 00:00:46.760 --> 00:00:49.020 We always want to go step-by-step 19 00:00:49.020 --> 00:00:50.730 when we do software development. 20 00:00:50.730 --> 00:00:52.670 We wanna do this, make sure it works, 21 00:00:52.670 --> 00:00:54.700 and then we can move on to the next bit. 22 00:00:54.700 --> 00:00:56.480 If you implement everything together, 23 00:00:56.480 --> 00:00:59.750 and then try to see if it works, you may find 24 00:00:59.750 --> 00:01:03.350 that it's not so easy to realise where the problem lies. 25 00:01:03.350 --> 00:01:06.100 So, going step-by-step, always a good idea. 26 00:01:06.100 --> 00:01:09.290 Let's go ahead into our templates, create a new file, 27 00:01:10.260 --> 00:01:12.820 which is going to be called create.jinja2, 28 00:01:12.820 --> 00:01:17.630 and in here we're gonna do the usual extends base.jinja2 29 00:01:20.080 --> 00:01:21.840 and then a block of content there. 30 00:01:24.310 --> 00:01:27.790 And inside this block we're going to put our form. 31 00:01:27.790 --> 00:01:30.510 First thing is a wee title, 32 00:01:30.510 --> 00:01:32.920 just so the user knows where they are. 33 00:01:34.380 --> 00:01:36.800 Then, we're going to include our form. 34 00:01:36.800 --> 00:01:37.633 Mark it. 35 00:01:40.140 --> 00:01:42.960 And inside a form, we're going to include a div. 36 00:01:44.430 --> 00:01:49.430 A div in HTML is just a horizontal block, 37 00:01:49.950 --> 00:01:53.140 so if you have two divs, for example this one here, 38 00:01:54.070 --> 00:01:56.300 and then this one here, they will appear 39 00:01:56.300 --> 00:02:00.920 one below the other, as opposed to one beside the other. 40 00:02:00.920 --> 00:02:04.030 So it's a good way of separating content in HTML. 41 00:02:04.030 --> 00:02:06.040 It doesn't really do anything on its own, 42 00:02:06.040 --> 00:02:07.890 but it's a good way of separating content. 43 00:02:07.890 --> 00:02:09.140 And the content we're going to separate 44 00:02:09.140 --> 00:02:10.930 is the different fields. 45 00:02:11.820 --> 00:02:16.820 First thing we're gonna do is add a label 46 00:02:17.110 --> 00:02:22.110 and the label is gonna be for this title field. 47 00:02:22.180 --> 00:02:25.900 The title field is gonna be here, input type text 48 00:02:25.900 --> 00:02:27.890 and the name is going to be title. 49 00:02:30.590 --> 00:02:35.410 Notice how the label has an opening tag and a closing tag, 50 00:02:35.410 --> 00:02:38.600 and inside it, you put what you want to go in the label. 51 00:02:38.600 --> 00:02:40.850 But the input field doesn't have anything inside it, 52 00:02:40.850 --> 00:02:42.850 because it's a blank field 53 00:02:42.850 --> 00:02:45.730 so you get what's called a self-closing tag. 54 00:02:45.730 --> 00:02:48.480 You get a tag that has this weird syntax 55 00:02:48.480 --> 00:02:50.070 where it's only a single tag 56 00:02:50.070 --> 00:02:52.080 but it has this forward slash at the end, 57 00:02:52.080 --> 00:02:54.280 this is called a self-closing tag. 58 00:02:54.280 --> 00:02:55.970 A tag that closes itself. 59 00:02:55.970 --> 00:03:00.850 The name of the field is what this for is going to target. 60 00:03:00.850 --> 00:03:05.850 So this tells HTML users that this label is for this field. 61 00:03:07.070 --> 00:03:11.060 Of course, when you see the text title beside a field, 62 00:03:11.060 --> 00:03:13.840 you know that that title is for that field. 63 00:03:13.840 --> 00:03:16.510 But if you're blind and you're using a screen reader, 64 00:03:16.510 --> 00:03:19.090 you may not see the contents of the label, 65 00:03:19.090 --> 00:03:20.250 but the screen reader will 66 00:03:20.250 --> 00:03:23.050 be able to look at this for property 67 00:03:23.050 --> 00:03:27.200 and tell you that this input field is a title. 68 00:03:27.200 --> 00:03:29.160 So it's always a good idea to have these fors, 69 00:03:29.160 --> 00:03:32.890 they're for screen readers, not for the rest of us, 70 00:03:32.890 --> 00:03:34.920 but it's a good idea nonetheless. 71 00:03:36.010 --> 00:03:38.440 Then in the other div, we're going to include a field 72 00:03:38.440 --> 00:03:40.740 for the contents of the post. 73 00:03:41.596 --> 00:03:46.530 So we're going to do label for content, content, like that, 74 00:03:48.440 --> 00:03:50.740 and then instead of an input type text, 75 00:03:50.740 --> 00:03:54.030 which is a single line text field, 76 00:03:54.030 --> 00:03:55.840 we're going to use a text area. 77 00:03:57.624 --> 00:04:00.040 A text area is just a multi-line field. 78 00:04:02.010 --> 00:04:03.450 Like that. 79 00:04:03.450 --> 00:04:07.290 And a text area does have to close, like that. 80 00:04:07.290 --> 00:04:09.500 It shouldn't be a self-closing tag. 81 00:04:10.670 --> 00:04:12.100 This is just another type of input 82 00:04:12.100 --> 00:04:14.390 which can span multiple lines. 83 00:04:14.390 --> 00:04:18.010 And finally we're going to include a final div, 84 00:04:19.240 --> 00:04:22.490 which is going to be an input of type submit. 85 00:04:24.720 --> 00:04:26.570 An input of type submit, essentially, 86 00:04:26.570 --> 00:04:28.810 is a button that the user can press, 87 00:04:28.810 --> 00:04:30.780 and when the user presses the button, 88 00:04:30.780 --> 00:04:35.410 they're going to send the data of the form to the server. 89 00:04:36.550 --> 00:04:39.050 Now that we've got this, let's go over to our app, 90 00:04:39.050 --> 00:04:42.750 run it, and see what happens when we access this endpoint. 91 00:04:42.750 --> 00:04:47.750 Let's go over to Chrome and access post/form 92 00:04:50.150 --> 00:04:53.290 and you get this nice looking form. 93 00:04:53.290 --> 00:04:56.130 Okay, I'll give you that is not terribly pretty, 94 00:04:56.130 --> 00:04:58.490 but nonetheless it is functional. 95 00:04:58.490 --> 00:05:02.680 You can put in your title here, like "My first blog post," 96 00:05:02.680 --> 00:05:05.940 and the content can be, "Hello, how are you doing?" 97 00:05:07.450 --> 00:05:11.200 Then you can submit and now look at what happens to the URL. 98 00:05:15.200 --> 00:05:17.270 The URL has changed, right? 99 00:05:17.270 --> 00:05:19.640 Now it has all of this stuff here. 100 00:05:20.720 --> 00:05:24.860 But it seemed like it loaded something. 101 00:05:24.860 --> 00:05:28.490 Now the fields are blank, but the URL has changed. 102 00:05:28.490 --> 00:05:29.640 So how to explain this? 103 00:05:30.980 --> 00:05:32.970 What was happening is the form 104 00:05:32.970 --> 00:05:37.410 is sending the data to a page. 105 00:05:37.410 --> 00:05:40.670 That page can then choose to use that data or not. 106 00:05:41.670 --> 00:05:44.200 What happens is, when you press submit, 107 00:05:44.200 --> 00:05:46.940 the browser sends another GET request 108 00:05:48.210 --> 00:05:52.390 to this URL /post/form 109 00:05:52.390 --> 00:05:55.200 and it includes behind that 110 00:05:55.200 --> 00:05:58.730 this, that is called the query string parameter, okay? 111 00:05:58.730 --> 00:06:02.810 This ?title= something and content equals something else. 112 00:06:03.870 --> 00:06:07.300 But because our Python code here, 113 00:06:07.300 --> 00:06:12.300 when you access this endpoint, only rendered a template, 114 00:06:12.590 --> 00:06:14.460 it doesn't use the data that it received 115 00:06:14.460 --> 00:06:16.410 in the query string parameters. 116 00:06:16.410 --> 00:06:18.380 It is unable to do anything with them, 117 00:06:18.380 --> 00:06:20.640 and all that happens is we re-rend the template 118 00:06:20.640 --> 00:06:22.690 and we don't use that data at all. 119 00:06:24.570 --> 00:06:25.640 We're gonna stop the app again 120 00:06:25.640 --> 00:06:27.680 because we're gonna restart it momentarily, 121 00:06:27.680 --> 00:06:28.730 but what we're going to do is, 122 00:06:28.730 --> 00:06:32.440 instead of sending the data to this endpoint, 123 00:06:32.440 --> 00:06:35.020 we're gonna send the data to a different endpoint. 124 00:06:35.020 --> 00:06:37.230 So, here in the form, we're gonna say 125 00:06:37.230 --> 00:06:42.230 action equals /post/create, okay? 126 00:06:44.170 --> 00:06:47.000 Instead of /post/form, now it's going to go 127 00:06:47.000 --> 00:06:51.430 into /post/create and we can create that endpoint. 128 00:06:51.430 --> 00:06:56.430 App.route/post/create, create post, 129 00:06:57.640 --> 00:07:00.180 and this, I'm actually just gonna call it create, 130 00:07:00.180 --> 00:07:05.180 just to keep it simple, this is going to access 131 00:07:05.340 --> 00:07:07.380 that data that's coming through the URL. 132 00:07:07.380 --> 00:07:11.250 Remember, this here is one server number one 5,000 133 00:07:13.556 --> 00:07:18.410 /post/create?title= blah blah 134 00:07:18.410 --> 00:07:21.840 and content equals something else. 135 00:07:22.810 --> 00:07:24.460 Yeah? 136 00:07:24.460 --> 00:07:26.690 We can access this stuff here, 137 00:07:26.690 --> 00:07:30.100 we can retrieve the title and the content. 138 00:07:30.100 --> 00:07:31.490 So let's do just that. 139 00:07:31.490 --> 00:07:34.970 Inside our create function, 140 00:07:34.970 --> 00:07:39.970 we're gonna say title is request.args.get title 141 00:07:40.080 --> 00:07:42.230 and we have to import request from Flask 142 00:07:42.230 --> 00:07:46.600 so let's go to the very top and say import request. 143 00:07:48.240 --> 00:07:51.500 This request thing here, it's a variable, 144 00:07:51.500 --> 00:07:52.900 it's like a global variable, 145 00:07:53.840 --> 00:07:57.810 is the request that is coming in to this endpoint. 146 00:07:57.810 --> 00:08:01.830 So the request right now, is this 147 00:08:01.830 --> 00:08:05.420 and it has some arguments which are these. 148 00:08:06.510 --> 00:08:09.080 And you can get a particular argument 149 00:08:09.080 --> 00:08:11.670 in order to retrieve its content. 150 00:08:11.670 --> 00:08:13.470 Essentially, Flask, behind-the-scenes, 151 00:08:13.470 --> 00:08:18.090 it's turning this into a dictionary and that's request.args. 152 00:08:18.090 --> 00:08:20.320 Then you can get a particular thing in that dictionary 153 00:08:20.320 --> 00:08:22.270 and we'll give you the content of that. 154 00:08:23.560 --> 00:08:27.770 Similarly, we can do content = request.args.get content 155 00:08:28.750 --> 00:08:31.330 then we can generate a new post ID, 156 00:08:31.330 --> 00:08:33.340 which is going to be len of posts. 157 00:08:34.250 --> 00:08:39.000 And finally we can say posts, post ID equal 158 00:08:40.500 --> 00:08:42.750 title is gonna be the title 159 00:08:42.750 --> 00:08:44.890 and content is gonna be the content. 160 00:08:46.540 --> 00:08:47.373 Like that. 161 00:08:48.950 --> 00:08:50.760 Now's a good point in time to make sure 162 00:08:50.760 --> 00:08:55.720 to also include an ID for the post in the body of the post. 163 00:08:58.530 --> 00:08:59.700 Like that. 164 00:08:59.700 --> 00:09:01.650 Just so when you access a particular post, 165 00:09:01.650 --> 00:09:03.720 you'll also have access to its ID. 166 00:09:03.720 --> 00:09:06.660 It's a useful thing to include in every post. 167 00:09:06.660 --> 00:09:09.310 So we're gonna go up here and also include that here. 168 00:09:10.950 --> 00:09:13.360 Okay, just a good thing to include 169 00:09:13.360 --> 00:09:14.960 in order to have the complete information 170 00:09:14.960 --> 00:09:16.640 when you do retrieve a post. 171 00:09:17.890 --> 00:09:21.670 Now that we've added this new post to our posts, 172 00:09:22.520 --> 00:09:26.630 we can return the user something else. 173 00:09:26.630 --> 00:09:30.570 So again, all this does is it accesses these arguments 174 00:09:30.570 --> 00:09:32.330 using request.args and gets a title 175 00:09:32.330 --> 00:09:34.680 and the content that came from the form, 176 00:09:34.680 --> 00:09:36.630 generates a new post ID, 177 00:09:36.630 --> 00:09:38.900 and then puts it into our dictionary. 178 00:09:38.900 --> 00:09:40.890 For example, if we create a new post 179 00:09:40.890 --> 00:09:44.060 and pass it some values here, len of posts will be one 180 00:09:44.060 --> 00:09:47.040 because we've got one post right now, 181 00:09:47.040 --> 00:09:51.000 and what we'll do is we'll say post one equal this new post. 182 00:09:52.010 --> 00:09:55.900 And at the end, we're gonna say return 183 00:09:55.900 --> 00:09:57.950 and here's a bit more complicated 184 00:09:57.950 --> 00:10:01.530 redirect URL for post, 185 00:10:01.530 --> 00:10:03.080 post ID equal 186 00:10:04.950 --> 00:10:05.783 post ID. 187 00:10:07.360 --> 00:10:09.530 So a couple of things are going on here. 188 00:10:09.530 --> 00:10:11.250 The first thing is this URL for. 189 00:10:12.320 --> 00:10:15.120 The URL for, which we're gonna import in just a moment, 190 00:10:15.120 --> 00:10:17.840 URL for takes in a function name, 191 00:10:19.090 --> 00:10:23.310 takes in the function name and returns a URL, 192 00:10:23.310 --> 00:10:26.860 an address that we want. 193 00:10:26.860 --> 00:10:29.190 In this case, it takes the post function name, 194 00:10:29.190 --> 00:10:31.600 which is this function defined up here, 195 00:10:31.600 --> 00:10:34.670 and it's gonna give us this URL. 196 00:10:36.380 --> 00:10:38.380 Instead of hard-coding the URL 197 00:10:38.380 --> 00:10:41.200 in here directly, we can use the URL for, 198 00:10:41.200 --> 00:10:44.270 and that way we can change this later on if we want. 199 00:10:44.270 --> 00:10:46.620 For example, let's say we wanna change it to, I don't know, 200 00:10:46.620 --> 00:10:50.930 posts/something, this will still work, 201 00:10:50.930 --> 00:10:53.180 because we've not changed the function name. 202 00:10:54.150 --> 00:10:56.770 So Flask recommends using this URL for 203 00:10:56.770 --> 00:11:00.710 in order to generate URLs instead of hard-coding them. 204 00:11:00.710 --> 00:11:04.600 And it also allows us to give the arguments that it needs. 205 00:11:04.600 --> 00:11:09.600 So the post URL needs a post ID in order to be complete, 206 00:11:10.700 --> 00:11:14.160 and we can do that inside the URL for function. 207 00:11:15.430 --> 00:11:18.480 The redirect is wrapping this URL for 208 00:11:18.480 --> 00:11:20.920 and what it does is it sends a response back 209 00:11:20.920 --> 00:11:23.350 to the browser telling the browser 210 00:11:23.350 --> 00:11:26.400 that it should actually not load this page, 211 00:11:26.400 --> 00:11:29.250 it should go and load this page instead. 212 00:11:29.250 --> 00:11:31.860 So, essentially, the browser loads this 213 00:11:31.860 --> 00:11:33.830 and then it receives this information 214 00:11:33.830 --> 00:11:35.750 and then it goes and loads the other thing. 215 00:11:35.750 --> 00:11:39.260 Browsers are already wired up to understand this, 216 00:11:39.260 --> 00:11:42.000 so that's why it works, you can send the browser 217 00:11:42.000 --> 00:11:44.100 to go to somewhere else and they'll do it. 218 00:11:45.210 --> 00:11:47.820 Okay, let's go up and import those two. 219 00:11:48.830 --> 00:11:51.090 We wanna import URL for and redirect 220 00:11:52.350 --> 00:11:54.520 and now when we create a new post, 221 00:11:54.520 --> 00:11:56.000 we pass it in the title and content, 222 00:11:56.000 --> 00:11:57.510 we add it to our database, 223 00:11:57.510 --> 00:12:00.390 and then we send the user to the post page 224 00:12:00.390 --> 00:12:01.940 for that specific post. 225 00:12:01.940 --> 00:12:04.890 So as soon as you create a post, you'll be sent back 226 00:12:04.890 --> 00:12:07.570 to the post page that you've just created. 227 00:12:07.570 --> 00:12:09.720 Let's go and run our app, and try this out. 228 00:12:11.780 --> 00:12:12.780 So what we're gonna do, 229 00:12:12.780 --> 00:12:16.030 is we are going to delete this query string parameter. 230 00:12:18.140 --> 00:12:19.360 We're going to refresh this page 231 00:12:19.360 --> 00:12:21.970 and now we're gonna enter something here. 232 00:12:21.970 --> 00:12:26.970 "My first blog post," and "Hey, what are you reading?" 233 00:12:27.510 --> 00:12:29.420 And then submit, and as soon as submit happens, 234 00:12:29.420 --> 00:12:32.160 you know what's gonna happen, the URL's gonna change, 235 00:12:32.160 --> 00:12:37.160 we're gonna send a request to /post/create, 236 00:12:37.500 --> 00:12:39.350 that's gonna process this function here, 237 00:12:39.350 --> 00:12:40.870 add something to our database, 238 00:12:40.870 --> 00:12:44.540 and then it's gonna redirect us to /post/one. 239 00:12:46.000 --> 00:12:48.560 Let's press submit and there you have it. 240 00:12:48.560 --> 00:12:51.010 And it happens so quickly, you can't even see it 241 00:12:51.010 --> 00:12:53.940 because there's really nothing much happening 242 00:12:53.940 --> 00:12:56.510 in the background, but this has now been added 243 00:12:56.510 --> 00:12:59.680 to our database, you can see we're in /post/one, 244 00:12:59.680 --> 00:13:02.300 and our new post contents have appeared here. 245 00:13:05.230 --> 00:13:08.020 So this is starting to get really cool. 246 00:13:08.020 --> 00:13:10.280 Now we can get information from our users, 247 00:13:10.280 --> 00:13:13.570 add it to a database, you know, send them to other places, 248 00:13:13.570 --> 00:13:15.490 display information and so forth. 249 00:13:16.920 --> 00:13:18.560 I hope you're starting to see the power 250 00:13:18.560 --> 00:13:20.340 of what Flask can do. 251 00:13:20.340 --> 00:13:22.240 I really love Flask and I'm really passionate 252 00:13:22.240 --> 00:13:24.370 about developing Flask applications 253 00:13:24.370 --> 00:13:26.190 because it's so simple. 254 00:13:26.190 --> 00:13:30.530 And it's all Python, all that's happening here is this. 255 00:13:30.530 --> 00:13:33.100 This is what Flask gives you, really. 256 00:13:33.100 --> 00:13:35.810 This routing, you know, access to the request, 257 00:13:35.810 --> 00:13:39.600 rendering templates, the rest, databases, 258 00:13:40.970 --> 00:13:43.420 all your business logic in terms of creating new posts 259 00:13:43.420 --> 00:13:46.010 and so forth, is all Python. 260 00:13:46.010 --> 00:13:48.690 And that gives you a lot of flexibility. 261 00:13:48.690 --> 00:13:51.470 There are other web frameworks apart from Flask 262 00:13:51.470 --> 00:13:55.160 that can be a bit more complex to use, such as Django, 263 00:13:55.160 --> 00:13:57.100 that require a bit more up-front knowledge, 264 00:13:57.100 --> 00:13:58.090 but Flask does not, 265 00:13:58.090 --> 00:14:01.200 that's why I'm really liking how Flask works. 266 00:14:01.200 --> 00:14:03.240 And this is what I do at my job 267 00:14:03.240 --> 00:14:04.990 and in many other quarters as well. 268 00:14:06.210 --> 00:14:08.070 So this was the end of the video, 269 00:14:08.070 --> 00:14:10.900 just wanted to show you how to send the user 270 00:14:10.900 --> 00:14:12.150 to a post they've just created 271 00:14:12.150 --> 00:14:14.240 and how to create new posts. 272 00:14:14.240 --> 00:14:16.560 We're going to move over to the next video 273 00:14:16.560 --> 00:14:19.600 to add posts in a slightly different manner. 274 00:14:19.600 --> 00:14:20.550 I'll see you there.