1 00:00:00,000 --> 00:00:00,562 2 00:00:00,562 --> 00:00:01,270 NICK WONG: Hello. 3 00:00:01,270 --> 00:00:03,070 So my name is Nick. 4 00:00:03,070 --> 00:00:05,706 And this is CS50 seminars. 5 00:00:05,706 --> 00:00:08,080 I'm going to be covering a little bit of web development. 6 00:00:08,080 --> 00:00:12,040 I think the title of this seminar is Basics of Web Development with Python 7 00:00:12,040 --> 00:00:12,790 and Django. 8 00:00:12,790 --> 00:00:16,350 Unsurprisingly, we'll be using Python and Django. 9 00:00:16,350 --> 00:00:18,280 To say this is the basics of web development 10 00:00:18,280 --> 00:00:19,960 is probably an overstatement. 11 00:00:19,960 --> 00:00:23,190 It will be a very, very brief dive into web development. 12 00:00:23,190 --> 00:00:24,397 And I get about an hour. 13 00:00:24,397 --> 00:00:26,980 And I'm going to try and cover as much Python, as much Django, 14 00:00:26,980 --> 00:00:30,520 and as much web development as I can. 15 00:00:30,520 --> 00:00:33,010 Currently, we are looking at my beautiful screen saver. 16 00:00:33,010 --> 00:00:34,430 I'm a huge fan. 17 00:00:34,430 --> 00:00:35,230 I didn't write it. 18 00:00:35,230 --> 00:00:37,417 It's basically just borrowed from The Matrix. 19 00:00:37,417 --> 00:00:39,250 I was recently told that The Matrix actually 20 00:00:39,250 --> 00:00:43,320 used a Japanese cookbook's characters, I think, for the things that come across. 21 00:00:43,320 --> 00:00:46,640 I am still in trying to get that to work. 22 00:00:46,640 --> 00:00:48,950 But we're going to just dive right in. 23 00:00:48,950 --> 00:00:54,600 So if you wants to see some code, if you go to this GitHub repository, 24 00:00:54,600 --> 00:00:59,450 I've built a bunch of stages for the app that we're going to be building today. 25 00:00:59,450 --> 00:01:04,390 I'm going to talk a little bit about what Django is, why I like using it, 26 00:01:04,390 --> 00:01:06,245 some of the frameworks and ideas behind it. 27 00:01:06,245 --> 00:01:08,620 And then we're going to go right into just kind of seeing 28 00:01:08,620 --> 00:01:10,300 how that kind of all comes together. 29 00:01:10,300 --> 00:01:14,270 I'm luckily not going to be doing a whole lot of live coding today. 30 00:01:14,270 --> 00:01:17,330 Live coding is one of the banes of my existence. 31 00:01:17,330 --> 00:01:18,670 I hate it. 32 00:01:18,670 --> 00:01:21,950 I will never, ever successfully live code entirely. 33 00:01:21,950 --> 00:01:23,800 I think I spend most of it debugging. 34 00:01:23,800 --> 00:01:25,090 And I make a lot of typos. 35 00:01:25,090 --> 00:01:29,530 So I have pre-built most of this code. 36 00:01:29,530 --> 00:01:30,480 Knock on wood. 37 00:01:30,480 --> 00:01:31,009 And so yeah. 38 00:01:31,009 --> 00:01:32,800 If you go to this GitHub repository, you're 39 00:01:32,800 --> 00:01:36,160 welcome to clone it, download it, fork it, whatever you'd like. 40 00:01:36,160 --> 00:01:38,540 There's all sorts of stuff on there. 41 00:01:38,540 --> 00:01:43,360 The latest directory, I think, has actually the thing that works the most. 42 00:01:43,360 --> 00:01:45,460 It's the one that's deployed. 43 00:01:45,460 --> 00:01:47,740 This is actually a live app on Heroku. 44 00:01:47,740 --> 00:01:50,200 I will mention a little bit, there are some things 45 00:01:50,200 --> 00:01:53,440 that aren't related directly to the topics of the seminar. 46 00:01:53,440 --> 00:01:56,915 We'll be talking a little bit about Heroku just briefly. 47 00:01:56,915 --> 00:02:00,040 And we'll kind of briefly skim over some Bootstrap and JavaScript and stuff 48 00:02:00,040 --> 00:02:00,370 like that. 49 00:02:00,370 --> 00:02:02,203 They're just not the focuses of the seminar. 50 00:02:02,203 --> 00:02:04,540 So I probably won't explain them very well or at all. 51 00:02:04,540 --> 00:02:07,510 I'll just kind of mentioned that this is where those are. 52 00:02:07,510 --> 00:02:11,740 There's a lot of great documentation for both Heroku and Bootstrap. 53 00:02:11,740 --> 00:02:13,870 JavaScript is questionable. 54 00:02:13,870 --> 00:02:16,390 And so if you're more interested in that, 55 00:02:16,390 --> 00:02:18,570 you're welcome to go and figure that one out. 56 00:02:18,570 --> 00:02:20,560 They're fully implemented in the code base. 57 00:02:20,560 --> 00:02:23,220 So hopefully not too bad. 58 00:02:23,220 --> 00:02:25,840 Yeah, getting right into it. 59 00:02:25,840 --> 00:02:30,610 Basically, Python, beautiful basically multipurpose language, super versatile. 60 00:02:30,610 --> 00:02:32,110 You can use it for machine learning. 61 00:02:32,110 --> 00:02:35,380 You can use it for computer vision, data processing, web development, 62 00:02:35,380 --> 00:02:37,060 which is what we'll be doing here. 63 00:02:37,060 --> 00:02:38,740 Web development is a very vague term. 64 00:02:38,740 --> 00:02:43,390 It means roughly just building things that go onto the internet. 65 00:02:43,390 --> 00:02:45,700 That's roughly the idea. 66 00:02:45,700 --> 00:02:48,820 I think people generally assign a bunch of terms to it 67 00:02:48,820 --> 00:02:54,340 that sound really cool, like full stack, back end, front end developer. 68 00:02:54,340 --> 00:02:57,250 We're not really going to be in any one of those particular things. 69 00:02:57,250 --> 00:03:01,700 I guess this is probably close-ish to a full stack, whatever that means. 70 00:03:01,700 --> 00:03:06,820 And so we will basically be building an app entirely from scratch in Python. 71 00:03:06,820 --> 00:03:09,190 All of it is in Python minus the front end stuff, which 72 00:03:09,190 --> 00:03:11,800 will be in HTML, JavaScript, and CSS. 73 00:03:11,800 --> 00:03:14,950 But the stuff in the back, the things that make everything work 74 00:03:14,950 --> 00:03:16,120 are in Python. 75 00:03:16,120 --> 00:03:18,045 And Python is a really cool language. 76 00:03:18,045 --> 00:03:19,420 It does all sorts of cool things. 77 00:03:19,420 --> 00:03:21,680 And it does them pretty well. 78 00:03:21,680 --> 00:03:23,710 And what I mean by that is it's pretty readable. 79 00:03:23,710 --> 00:03:27,790 I can look at some code and pretty quickly understand what's going on. 80 00:03:27,790 --> 00:03:29,240 It's extremely modular. 81 00:03:29,240 --> 00:03:31,720 So there are these modules, and you import them. 82 00:03:31,720 --> 00:03:36,010 And they each have their own functionality and things that they do. 83 00:03:36,010 --> 00:03:41,440 I'm generally a fan of clean and elegant code. 84 00:03:41,440 --> 00:03:42,250 Now, I say that. 85 00:03:42,250 --> 00:03:43,916 And then we're going to look at my code. 86 00:03:43,916 --> 00:03:47,630 And I'm sure there is someone out there who will go, ah, that's not clean. 87 00:03:47,630 --> 00:03:48,340 It's not elegant. 88 00:03:48,340 --> 00:03:49,540 And I will agree. 89 00:03:49,540 --> 00:03:51,670 That's correct. 90 00:03:51,670 --> 00:03:53,260 It can always be improved. 91 00:03:53,260 --> 00:03:56,680 But generally speaking, I am always looking towards that paradigm. 92 00:03:56,680 --> 00:04:00,850 And because of that, I particularly like Django as a framework. 93 00:04:00,850 --> 00:04:03,130 Here at CS50, we actually teach the framework 94 00:04:03,130 --> 00:04:05,350 of Flask, which is very similar. 95 00:04:05,350 --> 00:04:07,960 There are a lot of similarities between the two. 96 00:04:07,960 --> 00:04:13,120 But it's a little bit, I think, more small-scale. 97 00:04:13,120 --> 00:04:17,170 And then we kind of teach like all three separately. 98 00:04:17,170 --> 00:04:21,250 The databases, the controlling part of it, and then the front end 99 00:04:21,250 --> 00:04:24,520 are all kind of separated in CS50's way of teaching it, where we teach 100 00:04:24,520 --> 00:04:27,910 Flask for the back end controller part. 101 00:04:27,910 --> 00:04:30,590 We teach Jinja2 as our templating engine. 102 00:04:30,590 --> 00:04:31,840 So how do we control HTML? 103 00:04:31,840 --> 00:04:33,100 How do we generate that? 104 00:04:33,100 --> 00:04:36,520 And then we use, I believe, MySQL for the back end. 105 00:04:36,520 --> 00:04:38,210 Django is kind of all three in one. 106 00:04:38,210 --> 00:04:39,899 It just brings them all together. 107 00:04:39,899 --> 00:04:41,440 Django has its own templating engine. 108 00:04:41,440 --> 00:04:44,680 It's very similar if you've been following along with CS50 stuff. 109 00:04:44,680 --> 00:04:46,420 It's very similar to Jinja1. 110 00:04:46,420 --> 00:04:50,810 And then a lot of its paradigms for how things are controlled in the back 111 00:04:50,810 --> 00:04:57,130 and used are also quite similar, though a little bit more Pythonic, I think. 112 00:04:57,130 --> 00:04:58,450 That's a dangerous statement. 113 00:04:58,450 --> 00:05:00,533 We'll say that I just like them a little bit more. 114 00:05:00,533 --> 00:05:02,390 That's more of a personal choice. 115 00:05:02,390 --> 00:05:07,600 And then I believe we're actually using the same database back end as MySQL. 116 00:05:07,600 --> 00:05:08,800 We're using MySQL. 117 00:05:08,800 --> 00:05:12,040 However, it doesn't necessarily matter you can actually swap back ends out 118 00:05:12,040 --> 00:05:12,820 underneath Django. 119 00:05:12,820 --> 00:05:15,140 And it's pretty quick, very convenient. 120 00:05:15,140 --> 00:05:19,097 And we'll see later that deploying to Heroku, that is very convenient. 121 00:05:19,097 --> 00:05:20,680 Well, we might not see it a whole lot. 122 00:05:20,680 --> 00:05:22,220 But I'll point it out. 123 00:05:22,220 --> 00:05:27,310 So yeah, Django makes all of that come into one framework, one package. 124 00:05:27,310 --> 00:05:29,724 And it's super convenient to use. 125 00:05:29,724 --> 00:05:32,140 We'll talk a little bit about downloading the dependencies 126 00:05:32,140 --> 00:05:32,639 and things. 127 00:05:32,639 --> 00:05:35,590 But it's basically just Django. 128 00:05:35,590 --> 00:05:38,140 And then we'll talk a little bit about-- 129 00:05:38,140 --> 00:05:41,740 I'm using Waitress as the server for Django, 130 00:05:41,740 --> 00:05:45,130 because Django comes with some built-in controllers for running 131 00:05:45,130 --> 00:05:49,090 a server locally and abroad, remotely. 132 00:05:49,090 --> 00:05:55,240 And that isn't super suitable to even basic developmental purposes, 133 00:05:55,240 --> 00:05:57,040 except for local development. 134 00:05:57,040 --> 00:05:59,950 And since we put it on Heroku, I figured it would be a decent time 135 00:05:59,950 --> 00:06:03,100 to throw out that Waitress is a really great platform for actually running 136 00:06:03,100 --> 00:06:05,060 these sorts of things. 137 00:06:05,060 --> 00:06:10,102 But yeah, in Django, there are three main ideas underneath this framework. 138 00:06:10,102 --> 00:06:12,810 And when people say framework, they can mean all sorts of things. 139 00:06:12,810 --> 00:06:15,340 What I mean here is that this is a platform 140 00:06:15,340 --> 00:06:20,420 on which you can build pretty quick, very clean, very versatile web apps. 141 00:06:20,420 --> 00:06:22,090 And it's built entirely in Python. 142 00:06:22,090 --> 00:06:23,290 So I'm a huge fan. 143 00:06:23,290 --> 00:06:25,120 I'm kind of addicted to Python. 144 00:06:25,120 --> 00:06:29,480 And I've really learned to love Django a lot. 145 00:06:29,480 --> 00:06:31,880 So in Django, these three main ideas are actually 146 00:06:31,880 --> 00:06:34,670 shared across a lot of the web development space, 147 00:06:34,670 --> 00:06:37,370 except it's called a little bit different of a thing. 148 00:06:37,370 --> 00:06:40,860 So there's this acronym, MVC, models, views, and controllers. 149 00:06:40,860 --> 00:06:43,370 That's kind of the general web development term. 150 00:06:43,370 --> 00:06:45,320 Because of the way that Django is set up, 151 00:06:45,320 --> 00:06:49,849 we actually call MVT, which is models, views, and templates. 152 00:06:49,849 --> 00:06:51,890 And it ends up swapping two of the terms roughly, 153 00:06:51,890 --> 00:06:54,824 as far as position goes, but otherwise not too bad. 154 00:06:54,824 --> 00:06:56,990 So I'm going to talk about it in the Django context, 155 00:06:56,990 --> 00:07:00,020 because I promise the seminar will be mostly about Python and Django, 156 00:07:00,020 --> 00:07:02,600 with definitely an emphasis on Django. 157 00:07:02,600 --> 00:07:06,540 And so models are very cool. 158 00:07:06,540 --> 00:07:09,890 If you want to look at what they are in Python, they are in this file, 159 00:07:09,890 --> 00:07:11,390 models.py. 160 00:07:11,390 --> 00:07:12,740 They are classes in Python. 161 00:07:12,740 --> 00:07:14,990 If you understand Python's classes, if you understand 162 00:07:14,990 --> 00:07:17,270 classes and inheritance and things like that, 163 00:07:17,270 --> 00:07:19,640 then you understand models in Django. 164 00:07:19,640 --> 00:07:23,020 And you might be like, whooptie-doo, models, cool, don't really care. 165 00:07:23,020 --> 00:07:25,100 But models are our database. 166 00:07:25,100 --> 00:07:27,770 That is how we represent data in our database. 167 00:07:27,770 --> 00:07:32,220 Each individual item, you could roughly think of it as a table in a database. 168 00:07:32,220 --> 00:07:34,640 And so Django has this high-level abstraction 169 00:07:34,640 --> 00:07:36,800 for how we represent data in our database. 170 00:07:36,800 --> 00:07:39,380 And it does it in a way that is extremely congruent with how 171 00:07:39,380 --> 00:07:41,180 Python represents classes. 172 00:07:41,180 --> 00:07:42,990 In fact, they are Python classes. 173 00:07:42,990 --> 00:07:45,800 And so that's super convenient for the, I will say, 174 00:07:45,800 --> 00:07:49,460 intermediate or aspiring or advanced Pythonic developer. 175 00:07:49,460 --> 00:07:53,180 And I'm a huge fan of just being able to write classes for things 176 00:07:53,180 --> 00:07:58,170 and not really have to worry about SQL, SQL syntax, or any of that. 177 00:07:58,170 --> 00:08:02,390 For example, I haven't had to debug a SQL error message since-- 178 00:08:02,390 --> 00:08:05,190 well, I guess since teaching CS50. 179 00:08:05,190 --> 00:08:08,570 And so I'm a huge fan of the way models are written in Django. 180 00:08:08,570 --> 00:08:12,080 The only thing that I think is particularly troublesome in Django, 181 00:08:12,080 --> 00:08:14,791 and we will talk about it, are these things called migrations. 182 00:08:14,791 --> 00:08:16,040 So you build all these models. 183 00:08:16,040 --> 00:08:16,970 You write all these models down. 184 00:08:16,970 --> 00:08:17,480 They're beautiful. 185 00:08:17,480 --> 00:08:18,188 They're eloquent. 186 00:08:18,188 --> 00:08:19,797 They're perfectly well-written. 187 00:08:19,797 --> 00:08:22,130 And then you have to migrate them onto your application. 188 00:08:22,130 --> 00:08:24,410 And what that means is that you have to tell Django 189 00:08:24,410 --> 00:08:28,400 how these tables should be structured, how things should actually be designed. 190 00:08:28,400 --> 00:08:30,440 And you actually make these migrations first. 191 00:08:30,440 --> 00:08:31,690 They live in their own folder. 192 00:08:31,690 --> 00:08:33,330 And we'll talk about them a little bit. 193 00:08:33,330 --> 00:08:34,820 And then you have to actually migrate them over. 194 00:08:34,820 --> 00:08:37,528 If you don't do that, nothing gets actually changed in your data. 195 00:08:37,528 --> 00:08:39,076 It's a bunch of paper changes. 196 00:08:39,076 --> 00:08:41,659 And I think that that's one of the troublesome parts of Django 197 00:08:41,659 --> 00:08:42,260 development. 198 00:08:42,260 --> 00:08:43,807 It's pretty well done, I think. 199 00:08:43,807 --> 00:08:45,890 I couldn't think of, necessarily, something better 200 00:08:45,890 --> 00:08:47,090 off the top of my own head. 201 00:08:47,090 --> 00:08:50,070 But it's a little frustrating. 202 00:08:50,070 --> 00:08:52,680 I have lost lots of data before because of that. 203 00:08:52,680 --> 00:08:55,350 And to be clear, that is not the Django developer's fault. 204 00:08:55,350 --> 00:08:56,670 That it's certainly my own. 205 00:08:56,670 --> 00:08:58,830 And that's my own confusion and then experience. 206 00:08:58,830 --> 00:09:03,640 So we'll try and clarify a little bit of that as we go. 207 00:09:03,640 --> 00:09:07,170 Let's see, the next part is views, the V of MVT. 208 00:09:07,170 --> 00:09:11,340 And so views are basically Django's way of controlling 209 00:09:11,340 --> 00:09:13,350 what happens in the back. 210 00:09:13,350 --> 00:09:18,240 So you can think of it as, in web development or in the web in general, 211 00:09:18,240 --> 00:09:20,310 there are users or clients. 212 00:09:20,310 --> 00:09:22,980 I might refer to it as browser-side, client-side, user-side. 213 00:09:22,980 --> 00:09:26,160 Basically, I just mean the person with the laptop accessing our website. 214 00:09:26,160 --> 00:09:27,270 Excuse me. 215 00:09:27,270 --> 00:09:31,470 Or the phone or however they're getting to our website, they are the client. 216 00:09:31,470 --> 00:09:34,290 And that user is going to send some sort of request, 217 00:09:34,290 --> 00:09:38,280 preferably through HTTP or HTTPS, actually, would be ideal. 218 00:09:38,280 --> 00:09:41,880 And that request might be some form of get request or post. 219 00:09:41,880 --> 00:09:44,860 And they'll send that to me, the server-side. 220 00:09:44,860 --> 00:09:48,420 And I will generally try to refer to myself as server-side, everything else 221 00:09:48,420 --> 00:09:51,150 as client-side, since I am developing. 222 00:09:51,150 --> 00:09:55,230 And on that side, on my side, on the server-side, 223 00:09:55,230 --> 00:09:57,600 I'm going to try and handle that request. 224 00:09:57,600 --> 00:10:00,480 I have to figure out where it was intended for, 225 00:10:00,480 --> 00:10:02,520 what I should do when it gets there. 226 00:10:02,520 --> 00:10:04,200 Should I process certain data from it? 227 00:10:04,200 --> 00:10:07,410 Do I assume certain data exists from it? 228 00:10:07,410 --> 00:10:09,270 There's all sorts of things to do with that. 229 00:10:09,270 --> 00:10:10,990 And that is Django's views. 230 00:10:10,990 --> 00:10:13,920 So there is a views.py for every app in Django. 231 00:10:13,920 --> 00:10:16,620 You might be wondering what the heck is an app in Django. 232 00:10:16,620 --> 00:10:18,180 And I will point that out shortly. 233 00:10:18,180 --> 00:10:20,763 Sorry, there's a little bit of a chicken and egg problem here. 234 00:10:20,763 --> 00:10:23,070 But we'll get there in a sec. 235 00:10:23,070 --> 00:10:27,090 And views in Django basically say, hey, what did you get. 236 00:10:27,090 --> 00:10:29,160 What kind of URL was parsed here? 237 00:10:29,160 --> 00:10:30,600 What kind of arguments are there? 238 00:10:30,600 --> 00:10:32,347 And then it handles them accordingly. 239 00:10:32,347 --> 00:10:35,180 And if that sounds vague, it's because it's actually just very open. 240 00:10:35,180 --> 00:10:36,013 It's very versatile. 241 00:10:36,013 --> 00:10:38,272 It can be used for all sorts of things. 242 00:10:38,272 --> 00:10:40,230 One of the things that is worth mentioning here 243 00:10:40,230 --> 00:10:43,200 is that Django's URL system is really pretty. 244 00:10:43,200 --> 00:10:47,160 I like the fact that there are no file extensions in their URL system, 245 00:10:47,160 --> 00:10:48,780 at least not built-in. 246 00:10:48,780 --> 00:10:55,830 Everything is just domain name slash whatever without a .html, .php, 247 00:10:55,830 --> 00:10:56,850 or whatever it is. 248 00:10:56,850 --> 00:10:59,040 And I particularly enjoy that. 249 00:10:59,040 --> 00:11:02,610 It's also very easy to alias a bunch of URLs to the same view. 250 00:11:02,610 --> 00:11:04,110 You can do all sorts of things. 251 00:11:04,110 --> 00:11:07,710 It's very, very well-designed, I think. 252 00:11:07,710 --> 00:11:09,095 So there are views for Django. 253 00:11:09,095 --> 00:11:11,970 We'll cover each of these things in a little bit more concrete detail 254 00:11:11,970 --> 00:11:13,142 in a moment. 255 00:11:13,142 --> 00:11:16,350 And then there are templates, which is basically the way that Django actually 256 00:11:16,350 --> 00:11:17,900 represents HTML. 257 00:11:17,900 --> 00:11:19,650 And the reason they're called templates is 258 00:11:19,650 --> 00:11:24,510 because it's not written in pure HTML on the server side. 259 00:11:24,510 --> 00:11:29,250 It is actually written in a mixture of a HTML, JavaScript, CSS, the standards, 260 00:11:29,250 --> 00:11:31,830 and Django's templating engine. 261 00:11:31,830 --> 00:11:35,220 And so if you've ever used a templating engine before, you've got it. 262 00:11:35,220 --> 00:11:36,600 But if you haven't, no worries. 263 00:11:36,600 --> 00:11:38,080 Templating engines are really cool. 264 00:11:38,080 --> 00:11:39,780 They give us a lot of power. 265 00:11:39,780 --> 00:11:43,860 We'll see it very early on that if we were to write an index page or a home 266 00:11:43,860 --> 00:11:47,250 page, and if we were to then write a other, 267 00:11:47,250 --> 00:11:50,160 maybe posts or articles page, and then an authors page, 268 00:11:50,160 --> 00:11:53,460 and then in each of these things, each one has like a nav bar-- 269 00:11:53,460 --> 00:11:56,880 but then I went and added a favorites page. 270 00:11:56,880 --> 00:11:59,010 And now I've got to go change each nav bar. 271 00:11:59,010 --> 00:12:02,850 And I'm going to overexaggerate how tedious that is when we get there. 272 00:12:02,850 --> 00:12:03,926 It's annoying. 273 00:12:03,926 --> 00:12:07,050 And not only is it annoying, but if you're working on a team of developers, 274 00:12:07,050 --> 00:12:10,230 it can lead to a lot of inconsistencies. 275 00:12:10,230 --> 00:12:14,010 Simply put, it can lead to a lot of inconsistencies in style. 276 00:12:14,010 --> 00:12:17,190 But even worse, it can lead to inconsistencies in thought process 277 00:12:17,190 --> 00:12:18,780 and actual design choices. 278 00:12:18,780 --> 00:12:20,610 And that can be really bad. 279 00:12:20,610 --> 00:12:22,680 And I said really bad as a vague, scary term. 280 00:12:22,680 --> 00:12:24,570 But it has a lot of implications. 281 00:12:24,570 --> 00:12:28,660 We might have a developer who forgets to do a certain thing in the navigation 282 00:12:28,660 --> 00:12:29,160 bar. 283 00:12:29,160 --> 00:12:32,310 And then whenever you get to customer support, you can't get back. 284 00:12:32,310 --> 00:12:33,510 Bummer. 285 00:12:33,510 --> 00:12:36,120 And those sorts of things might not necessarily 286 00:12:36,120 --> 00:12:39,600 matter to you, the developer, who knows your website very well. 287 00:12:39,600 --> 00:12:43,550 But to the average user trying to get to your website for the first time, 288 00:12:43,550 --> 00:12:46,860 it can be really frustrating not having an intuitive user interface. 289 00:12:46,860 --> 00:12:50,760 So following what does it mean to be a real user of your website 290 00:12:50,760 --> 00:12:53,149 whenever you're web developing is really important. 291 00:12:53,149 --> 00:12:55,440 What might be intuitive to you because you've sat there 292 00:12:55,440 --> 00:12:58,454 for 35 hours straight looking at this code 293 00:12:58,454 --> 00:13:00,870 might not be intuitive to the person who has never visited 294 00:13:00,870 --> 00:13:02,700 your website before in their lives. 295 00:13:02,700 --> 00:13:07,770 So we'll stick to a very basic standard of not 296 00:13:07,770 --> 00:13:10,590 quite the monolithic one-page website. 297 00:13:10,590 --> 00:13:14,760 I'm not a huge fan of those, although they are nice, and they have purpose. 298 00:13:14,760 --> 00:13:20,130 But we are going to be on kind of the thing in the front, nav bar at the top, 299 00:13:20,130 --> 00:13:22,620 navigate to any page in one click. 300 00:13:22,620 --> 00:13:26,610 And that is a kind of simplified version of a web development practice, which 301 00:13:26,610 --> 00:13:29,940 is basically just to keep everything as flat as possible, 302 00:13:29,940 --> 00:13:33,952 meaning that I don't have to click very far to get into everything. 303 00:13:33,952 --> 00:13:35,910 So we've covered a little bit about what Django 304 00:13:35,910 --> 00:13:39,111 is, a little bit about the paradigm underneath. 305 00:13:39,111 --> 00:13:40,110 Let's look at some code. 306 00:13:40,110 --> 00:13:43,360 So if you have looked at this GitHub repository, 307 00:13:43,360 --> 00:13:46,320 then you certainly know a little bit about what's going on. 308 00:13:46,320 --> 00:13:47,490 I left some READMEs there. 309 00:13:47,490 --> 00:13:48,180 I apologize. 310 00:13:48,180 --> 00:13:51,690 My sense of humor from this talk is actually bleeding through. 311 00:13:51,690 --> 00:13:55,140 You will get a sense of my sense of humor, and it's terrible. 312 00:13:55,140 --> 00:13:58,320 If you're interested, this is my command line. 313 00:13:58,320 --> 00:14:02,780 This is the repository that you hopefully have access to. 314 00:14:02,780 --> 00:14:05,370 And what we're going to look at is the actual code. 315 00:14:05,370 --> 00:14:10,350 So I labeled them in classic CS style starting at 0 and going up to 7. 316 00:14:10,350 --> 00:14:12,160 So there are 8 stages total. 317 00:14:12,160 --> 00:14:16,440 And we're going to say a goal is to get to stage 5. 318 00:14:16,440 --> 00:14:19,470 It's a decently complete web application. 319 00:14:19,470 --> 00:14:22,320 We'll ideally get to stage 6. 320 00:14:22,320 --> 00:14:27,150 And if there's magic in the world, we'll get to stage 7. 321 00:14:27,150 --> 00:14:29,399 So we're going to start at stage 0. 322 00:14:29,399 --> 00:14:31,440 And basically, we're going to spend a lot of time 323 00:14:31,440 --> 00:14:33,210 looking at this file structure here. 324 00:14:33,210 --> 00:14:35,850 So I'll expand that a little bit for you. 325 00:14:35,850 --> 00:14:38,410 And what you see here is there's this pycache directory. 326 00:14:38,410 --> 00:14:39,456 It gets ignored by Git. 327 00:14:39,456 --> 00:14:40,830 We're not too worried about that. 328 00:14:40,830 --> 00:14:42,720 This dv.sqlite3. 329 00:14:42,720 --> 00:14:48,120 Sorry, we use SQLite as the actual database structure. 330 00:14:48,120 --> 00:14:50,580 And then we have this manage.py, readme.md, 331 00:14:50,580 --> 00:14:54,990 which is just explaining what's going on, run.sh, and we have rango. 332 00:14:54,990 --> 00:14:56,599 And so actually, that's a great point. 333 00:14:56,599 --> 00:14:59,640 I'm going to tell you a little bit about what we're actually doing today, 334 00:14:59,640 --> 00:15:04,710 since that is a reasonable question that was probably asked a while ago. 335 00:15:04,710 --> 00:15:10,530 I thought it was really cute and punny/funny to say randomized Django 336 00:15:10,530 --> 00:15:13,270 blog, rango. 337 00:15:13,270 --> 00:15:13,770 Yeah. 338 00:15:13,770 --> 00:15:16,780 So that was a lot funnier to me at around 4:00 AM two days ago. 339 00:15:16,780 --> 00:15:18,570 But it's still kind of funny to me. 340 00:15:18,570 --> 00:15:20,040 And I hope you enjoy it. 341 00:15:20,040 --> 00:15:23,070 But the idea basically being a lot of people 342 00:15:23,070 --> 00:15:27,780 build their first Django app as some sort of basic blog. 343 00:15:27,780 --> 00:15:29,100 I'm kind of lazy. 344 00:15:29,100 --> 00:15:32,207 And I didn't really want to go stealing through web scraping 345 00:15:32,207 --> 00:15:33,540 a bunch of other people's blogs. 346 00:15:33,540 --> 00:15:37,290 So I figured, why not create some kind of randomized blog. 347 00:15:37,290 --> 00:15:38,730 It's not particularly pretty. 348 00:15:38,730 --> 00:15:42,220 But there are things you could do to improve on it. 349 00:15:42,220 --> 00:15:45,000 But again, this is definitely trying to just get 350 00:15:45,000 --> 00:15:48,510 through a very large number of practices and ideas 351 00:15:48,510 --> 00:15:50,010 in a very quick period of time. 352 00:15:50,010 --> 00:15:54,540 So what basically happened here is, instead of stage 00, 353 00:15:54,540 --> 00:15:59,760 you might do django-admin startproject of rango. 354 00:15:59,760 --> 00:16:02,460 And what that would actually end up doing-- 355 00:16:02,460 --> 00:16:05,630 and that command looks like this. 356 00:16:05,630 --> 00:16:06,740 Whoops. 357 00:16:06,740 --> 00:16:08,620 See, this is the problem with coding live. 358 00:16:08,620 --> 00:16:10,400 I can never spell. 359 00:16:10,400 --> 00:16:12,660 That implies that I could spell normally, I can't. 360 00:16:12,660 --> 00:16:13,490 Cool. 361 00:16:13,490 --> 00:16:16,970 So this command over here is what I might 362 00:16:16,970 --> 00:16:19,516 use to start a new project in Django. 363 00:16:19,516 --> 00:16:21,890 And you might have typed that into your console and been, 364 00:16:21,890 --> 00:16:23,870 like, command not found, Django admin. 365 00:16:23,870 --> 00:16:25,070 Why did you lie to me, Nick? 366 00:16:25,070 --> 00:16:26,280 And I apologize. 367 00:16:26,280 --> 00:16:28,550 I was not lying to you directly. 368 00:16:28,550 --> 00:16:32,449 Basically, you actually need to install Django first 369 00:16:32,449 --> 00:16:34,490 before you can actually run that sort of command. 370 00:16:34,490 --> 00:16:38,720 And so it is a PIP package you can do pip install of Django. 371 00:16:38,720 --> 00:16:41,630 I just did that, at least as far as building this project goes. 372 00:16:41,630 --> 00:16:43,280 And that will get us going. 373 00:16:43,280 --> 00:16:45,170 You'll notice in the left of my prompt, I 374 00:16:45,170 --> 00:16:48,560 have this little parenthetical rango over here. 375 00:16:48,560 --> 00:16:52,280 You're going to hear me say rango and Django and Python and oh, no 376 00:16:52,280 --> 00:16:53,710 frequently. 377 00:16:53,710 --> 00:16:57,350 But rango being the name of just a virtual environment that I setup. 378 00:16:57,350 --> 00:16:59,630 And virtual environments are in a great aspect 379 00:16:59,630 --> 00:17:04,819 of controlling which version of packages you're using in Python. 380 00:17:04,819 --> 00:17:07,010 They basically just say, hey, I only want 381 00:17:07,010 --> 00:17:12,619 to use this set of packages for this Python thing that I'm doing. 382 00:17:12,619 --> 00:17:14,849 So let's keep them all separate from each other. 383 00:17:14,849 --> 00:17:19,099 For example, if I'm using the Harvard Crimson's version of Django, 384 00:17:19,099 --> 00:17:22,690 I will have to go back a couple of decades. 385 00:17:22,690 --> 00:17:26,890 So we are basically saying here that we just 386 00:17:26,890 --> 00:17:32,260 want to use this particular project's versions of every Python package. 387 00:17:32,260 --> 00:17:35,230 It also means that I can just have those dependencies. 388 00:17:35,230 --> 00:17:39,370 And I can install them in a requirements.txt, for example. 389 00:17:39,370 --> 00:17:41,950 So if you go to that GitHub repository, then you're 390 00:17:41,950 --> 00:17:46,270 actually able to just do a pip install -r of all of these requirements. 391 00:17:46,270 --> 00:17:49,510 And that will set you up with all the requirements you could possibly need-- 392 00:17:49,510 --> 00:17:53,110 knock on wood-- for the latest version of this, as well 393 00:17:53,110 --> 00:17:54,800 as all the intermediates. 394 00:17:54,800 --> 00:17:56,396 So you're welcome to go do that. 395 00:17:56,396 --> 00:17:58,270 You're welcome to install them one at a time. 396 00:17:58,270 --> 00:17:59,200 I'm not your mother. 397 00:17:59,200 --> 00:18:02,620 You're welcome to do whatever you'd like. 398 00:18:02,620 --> 00:18:04,930 Beyond that, once you've gotten that done, 399 00:18:04,930 --> 00:18:06,680 you can run this Django admin command. 400 00:18:06,680 --> 00:18:09,790 And now I'm no longer lying to you. 401 00:18:09,790 --> 00:18:11,980 And it will actually do-- 402 00:18:11,980 --> 00:18:17,020 well, hopefully, it will do what I tell you it would do. 403 00:18:17,020 --> 00:18:19,900 So django-admin startproject rango will get 404 00:18:19,900 --> 00:18:22,270 you going with a project called rango. 405 00:18:22,270 --> 00:18:26,200 Now, Django-- oh, there's going to be some fun tongue twisters. 406 00:18:26,200 --> 00:18:29,530 Django tries to set everything up in a beautiful directory-based structure 407 00:18:29,530 --> 00:18:33,070 for you, meaning that when I ran this, I would actually have ended up 408 00:18:33,070 --> 00:18:35,290 with a directory called rango. 409 00:18:35,290 --> 00:18:39,370 Mine is called stage 0, because I built them into several separate stages. 410 00:18:39,370 --> 00:18:44,150 But it would then have inside of it another directory with the same name. 411 00:18:44,150 --> 00:18:46,030 Now, you might be wondering why do that. 412 00:18:46,030 --> 00:18:47,410 That sounds non-flat. 413 00:18:47,410 --> 00:18:50,230 It sounds very nested and hierarchical and annoying. 414 00:18:50,230 --> 00:18:53,740 And you'd be almost right, except that within a project, which 415 00:18:53,740 --> 00:18:58,060 is what this upper directory will be, the directory underneath 416 00:18:58,060 --> 00:19:01,480 in rango itself is actually the main or root 417 00:19:01,480 --> 00:19:03,790 app underneath our Django application. 418 00:19:03,790 --> 00:19:08,020 So within a Django project, you have applications that are installed. 419 00:19:08,020 --> 00:19:10,780 The first one that is created is actually one of the main ones. 420 00:19:10,780 --> 00:19:12,190 It is the main one. 421 00:19:12,190 --> 00:19:16,030 And it is generally where requests are going to go first. 422 00:19:16,030 --> 00:19:20,000 Now, you can configure the heck out of Django, no problem. 423 00:19:20,000 --> 00:19:24,040 So I'm going to say things in kind of this probabilistic way. 424 00:19:24,040 --> 00:19:25,450 You can generally do this. 425 00:19:25,450 --> 00:19:26,680 You can usually do this. 426 00:19:26,680 --> 00:19:29,860 It will usually be related to the default settings. 427 00:19:29,860 --> 00:19:33,860 But technically speaking, you could manipulate it however you'd like. 428 00:19:33,860 --> 00:19:37,190 So in this initial installation, there's very little that has to be done. 429 00:19:37,190 --> 00:19:38,860 I just got it running. 430 00:19:38,860 --> 00:19:41,180 That was all I wanted it to do. 431 00:19:41,180 --> 00:19:47,200 So what we're going to do is, if we go into stage_00, 432 00:19:47,200 --> 00:19:49,900 I can actually run this application totally reasonably 433 00:19:49,900 --> 00:19:52,880 from my local computer. 434 00:19:52,880 --> 00:19:57,520 So what I can do there is I can do python manage.py-- 435 00:19:57,520 --> 00:20:00,240 manage.py being the management interface for Django. 436 00:20:00,240 --> 00:20:03,790 So if I want to run a server, if I want to migrate my database, 437 00:20:03,790 --> 00:20:08,530 if I want to do all sorts of other things, I can do managed.py. 438 00:20:08,530 --> 00:20:10,890 And then we're going to do exactly that, runserver. 439 00:20:10,890 --> 00:20:15,400 0.0.0.0 is-- I always forget how many zeros there are in that. 440 00:20:15,400 --> 00:20:19,630 There are four, 0.0.0.0 is just kind of display on my computer 441 00:20:19,630 --> 00:20:21,730 and open the interface out to the public. 442 00:20:21,730 --> 00:20:27,430 8.8.8.8 is a nifty general port for development use. 443 00:20:27,430 --> 00:20:30,070 You'll notice that Django initially will give you this, 444 00:20:30,070 --> 00:20:31,720 you have 15 unapplied migrations. 445 00:20:31,720 --> 00:20:33,790 Those are all the admin page migrations. 446 00:20:33,790 --> 00:20:35,920 Admin is an interface built into Django. 447 00:20:35,920 --> 00:20:37,044 It's kind of cool. 448 00:20:37,044 --> 00:20:38,960 There's all sorts of things we can do with it. 449 00:20:38,960 --> 00:20:41,530 I'm not going to touch on too many of them during this talk. 450 00:20:41,530 --> 00:20:43,120 But it is a very useful interface. 451 00:20:43,120 --> 00:20:44,320 And it's worth looking up. 452 00:20:44,320 --> 00:20:46,730 I just think it's relatively intuitive. 453 00:20:46,730 --> 00:20:53,980 And so it'll tell me that I have at 0.0.0.0, 8.8.8.8 this thing running. 454 00:20:53,980 --> 00:20:57,550 I'm actually going to just go here in my web browser. 455 00:20:57,550 --> 00:21:00,640 I would say your web browser of choice will suffice. 456 00:21:00,640 --> 00:21:04,360 People generally disagree with my use of Safari as a web browser. 457 00:21:04,360 --> 00:21:05,710 But that's all right. 458 00:21:05,710 --> 00:21:09,910 So you'll see this cute little page from Django itself. 459 00:21:09,910 --> 00:21:10,780 We've done nothing. 460 00:21:10,780 --> 00:21:14,740 I literally just did a django-admin startproject, went into that directory, 461 00:21:14,740 --> 00:21:16,010 and ran the server. 462 00:21:16,010 --> 00:21:18,250 So we have very little to do in this stage. 463 00:21:18,250 --> 00:21:20,080 And you get this, it worked. 464 00:21:20,080 --> 00:21:22,360 You're on the right path. 465 00:21:22,360 --> 00:21:25,240 As long as you are there, congrats, you did it. 466 00:21:25,240 --> 00:21:27,790 So we are now running a web server. 467 00:21:27,790 --> 00:21:28,720 It's local. 468 00:21:28,720 --> 00:21:30,980 And I'm actually able to visit it and see what's up. 469 00:21:30,980 --> 00:21:32,620 There's nothing interesting really on here. 470 00:21:32,620 --> 00:21:34,150 There's a bunch of documentation on the bottom. 471 00:21:34,150 --> 00:21:36,025 Their documentation is beautiful, by the way. 472 00:21:36,025 --> 00:21:39,530 I would definitely recommend reading it or reading through it a little bit. 473 00:21:39,530 --> 00:21:42,305 Don't read it like a book, because that would be a little weird. 474 00:21:42,305 --> 00:21:43,430 Again, I'm not your mother. 475 00:21:43,430 --> 00:21:44,901 You do whatever you want. 476 00:21:44,901 --> 00:21:46,150 And so we kind of get to here. 477 00:21:46,150 --> 00:21:47,441 We see that things are working. 478 00:21:47,441 --> 00:21:48,370 We're glad. 479 00:21:48,370 --> 00:21:51,140 Everything's wired up a little bit, or at least mostly, correctly. 480 00:21:51,140 --> 00:21:54,400 Now, Django will output all of these things for you. 481 00:21:54,400 --> 00:21:56,894 You get to get a live log of what's going on. 482 00:21:56,894 --> 00:21:59,060 And when you're developing or when you're debugging, 483 00:21:59,060 --> 00:22:01,040 this is actually really useful. 484 00:22:01,040 --> 00:22:03,710 So development-wise, this is a great way to run the app. 485 00:22:03,710 --> 00:22:06,040 Excuse me. 486 00:22:06,040 --> 00:22:07,540 Oh, think I got some dust in my eye. 487 00:22:07,540 --> 00:22:09,010 That's fun. 488 00:22:09,010 --> 00:22:11,710 And there we go, I think. 489 00:22:11,710 --> 00:22:12,670 This is really useful. 490 00:22:12,670 --> 00:22:14,800 You can print all sorts of things to this console. 491 00:22:14,800 --> 00:22:16,787 You can actually use logging practices. 492 00:22:16,787 --> 00:22:19,120 Generally speaking, if you're running some sort web app, 493 00:22:19,120 --> 00:22:20,560 please use a real logger. 494 00:22:20,560 --> 00:22:22,330 There's a great article on Python logging 495 00:22:22,330 --> 00:22:24,160 mechanisms out there on the internet. 496 00:22:24,160 --> 00:22:27,730 It's like the first thing you get when you do "Python how to logging" 497 00:22:27,730 --> 00:22:29,150 on Google. 498 00:22:29,150 --> 00:22:32,080 And so I would definitely recommend reading through that as well. 499 00:22:32,080 --> 00:22:35,000 That is a fantastic practice for just keeping everything consistent. 500 00:22:35,000 --> 00:22:37,750 Logs are built in a really good way for just grepping through them 501 00:22:37,750 --> 00:22:39,335 and seeing what's going on. 502 00:22:39,335 --> 00:22:39,835 So cool. 503 00:22:39,835 --> 00:22:41,244 We've gotten through stage 0. 504 00:22:41,244 --> 00:22:43,160 We can pat ourselves on the back a little bit. 505 00:22:43,160 --> 00:22:45,670 And now we're going to Control-C out of that. 506 00:22:45,670 --> 00:22:48,640 And we're going to go figure out what is in stage 1. 507 00:22:48,640 --> 00:22:50,550 And I say that as if I don't know. 508 00:22:50,550 --> 00:22:52,960 But unfortunately, I do. 509 00:22:52,960 --> 00:22:53,980 Cool. 510 00:22:53,980 --> 00:22:59,262 So if we go into stage 1, there's now a new thing that exists. 511 00:22:59,262 --> 00:23:01,720 There's a new directory I'd like to draw your attention to. 512 00:23:01,720 --> 00:23:02,920 It's called web. 513 00:23:02,920 --> 00:23:06,550 And this one looks very similar to our base directory or our base 514 00:23:06,550 --> 00:23:08,290 application, rango. 515 00:23:08,290 --> 00:23:10,910 However, it has a few other things in it. 516 00:23:10,910 --> 00:23:14,590 And so when you do install another app in Django, 517 00:23:14,590 --> 00:23:17,890 which looks roughly like django-admin startapp-- 518 00:23:17,890 --> 00:23:19,960 and this is the command that was run for that. 519 00:23:19,960 --> 00:23:21,920 I'll bring that up to the top. 520 00:23:21,920 --> 00:23:22,840 We ran this command. 521 00:23:22,840 --> 00:23:25,430 And we got this web subdirectory. 522 00:23:25,430 --> 00:23:28,570 And what that did for us is it gave us an actual application that's 523 00:23:28,570 --> 00:23:31,960 going to kind of run underneath Django. 524 00:23:31,960 --> 00:23:36,790 And so it's a little bit strange, in that it itself is not really running. 525 00:23:36,790 --> 00:23:38,540 We're still running our main project. 526 00:23:38,540 --> 00:23:40,290 We're still using the management interface 527 00:23:40,290 --> 00:23:42,320 to run things, at least for now. 528 00:23:42,320 --> 00:23:46,810 But it is the thing that's actually doing our web deployment. 529 00:23:46,810 --> 00:23:49,490 And so there are a lot of different ways of doing this. 530 00:23:49,490 --> 00:23:53,680 You could run it as this monolithic, everything's under the rango app. 531 00:23:53,680 --> 00:23:56,320 And you don't do anything else. 532 00:23:56,320 --> 00:23:58,330 But I'm generally not a fan of doing that. 533 00:23:58,330 --> 00:24:00,610 I think separating things out by functionality 534 00:24:00,610 --> 00:24:01,810 is a really good practice. 535 00:24:01,810 --> 00:24:03,890 It makes debugging a lot easier. 536 00:24:03,890 --> 00:24:06,520 It also makes development with a team a lot better. 537 00:24:06,520 --> 00:24:09,020 And I say that, again, generalist statements. 538 00:24:09,020 --> 00:24:12,070 But what I mean by that is, if I'm on a team with three people, 539 00:24:12,070 --> 00:24:14,890 I want to work on the web app version of what's going on. 540 00:24:14,890 --> 00:24:17,620 He wants to work on the API version of what's going on. 541 00:24:17,620 --> 00:24:20,800 And she wants to work on making sure all of our URLs are beautiful 542 00:24:20,800 --> 00:24:24,370 and settings are configured correctly for production and development. 543 00:24:24,370 --> 00:24:28,840 Then we can all do that at the same time using some sort of version control 544 00:24:28,840 --> 00:24:31,030 and not step on each other's toes. 545 00:24:31,030 --> 00:24:33,430 If we were all working in a monolithic views.py, 546 00:24:33,430 --> 00:24:39,820 models.py, et cetera, then the API guy, the web guy, and probably 547 00:24:39,820 --> 00:24:42,880 our product manager woman are all going to conflict. 548 00:24:42,880 --> 00:24:44,350 And it's going to be a pain. 549 00:24:44,350 --> 00:24:46,030 We might all end up killing each other. 550 00:24:46,030 --> 00:24:50,530 So generally speaking, keeping things separated out has an actual purpose. 551 00:24:50,530 --> 00:24:51,907 There is a reason for that. 552 00:24:51,907 --> 00:24:53,740 And I think even in doing personal projects, 553 00:24:53,740 --> 00:24:56,800 it is a really good practice to get into that habit. 554 00:24:56,800 --> 00:24:59,410 It helps to make you a little bit more efficient too. 555 00:24:59,410 --> 00:25:02,350 Generally speaking, I would argue that there are plenty 556 00:25:02,350 --> 00:25:05,540 of arguments for why it's a good idea. 557 00:25:05,540 --> 00:25:07,810 So now you'll notice, or you might notice, 558 00:25:07,810 --> 00:25:10,690 I will point out to you that there are these kind of new directories. 559 00:25:10,690 --> 00:25:13,300 There's this migrations directory within our web app. 560 00:25:13,300 --> 00:25:16,720 You'll notice it does not exist in rango, the base app. 561 00:25:16,720 --> 00:25:19,450 However, in rango, we do have this static directory, 562 00:25:19,450 --> 00:25:23,405 which I believe it actually does exist in stage 0's rango. 563 00:25:23,405 --> 00:25:24,280 Oh, no, just kidding. 564 00:25:24,280 --> 00:25:24,880 Cool. 565 00:25:24,880 --> 00:25:26,749 So that is also a new directory. 566 00:25:26,749 --> 00:25:28,540 We're going to talk about that in a second. 567 00:25:28,540 --> 00:25:31,030 We've also changed some of the settings in this one. 568 00:25:31,030 --> 00:25:36,400 And we've added a basic URL and a basic view. 569 00:25:36,400 --> 00:25:38,230 And no models have been modified yet. 570 00:25:38,230 --> 00:25:40,670 So we're going to talk about that in a second. 571 00:25:40,670 --> 00:25:42,190 Let's start with static. 572 00:25:42,190 --> 00:25:48,130 So Django has a built-in system for static files. 573 00:25:48,130 --> 00:25:52,810 And static files can be notoriously annoying and difficult to configure. 574 00:25:52,810 --> 00:25:55,060 I'll do my best to explain them here. 575 00:25:55,060 --> 00:25:58,570 But honestly, it's worth playing around with it and really getting an intuition 576 00:25:58,570 --> 00:25:59,890 yourself. 577 00:25:59,890 --> 00:26:03,970 So static is what refers to all sorts of JavaScript, 578 00:26:03,970 --> 00:26:08,980 fonts, images, CSS in a Django web app. 579 00:26:08,980 --> 00:26:11,830 And so generally speaking, you're only going to have, really, 580 00:26:11,830 --> 00:26:14,260 three or four folders in static. 581 00:26:14,260 --> 00:26:17,200 I like to keep mine actually separated out, in that I actually 582 00:26:17,200 --> 00:26:19,180 separate out by app. 583 00:26:19,180 --> 00:26:22,730 So I say, underneath static, there's each app's name. 584 00:26:22,730 --> 00:26:25,930 And then under each app, there is each of the things 585 00:26:25,930 --> 00:26:28,930 that you want to actually control or have in the static directory. 586 00:26:28,930 --> 00:26:31,700 So admin has already been collected into here. 587 00:26:31,700 --> 00:26:37,840 The Django web management interface command is python3 manage.py. 588 00:26:37,840 --> 00:26:43,030 That'll be the management interface that I refer to is python3 manage.py. 589 00:26:43,030 --> 00:26:46,270 And then we can say something like collectstatic. 590 00:26:46,270 --> 00:26:48,610 And that will allow us to actually take all 591 00:26:48,610 --> 00:26:50,590 of the static things that exist somewhere 592 00:26:50,590 --> 00:26:53,320 and shove them to wherever they actually belong. 593 00:26:53,320 --> 00:26:57,790 And the reason I say that and such weird terms is that for now, 594 00:26:57,790 --> 00:27:01,340 that means just the things that you wrote here, keep them here. 595 00:27:01,340 --> 00:27:04,905 However, when we actually switch to some sort of real production environment, 596 00:27:04,905 --> 00:27:08,155 which I don't believe we'll have time to get to, but it is worth looking into, 597 00:27:08,155 --> 00:27:10,700 and there's great documentation on that as well, 598 00:27:10,700 --> 00:27:14,110 we might want to use some sort of content delivery network, or CDN, 599 00:27:14,110 --> 00:27:18,550 to actually move everything off of our personal server. 600 00:27:18,550 --> 00:27:22,060 Django itself and a lot of the services underneath it 601 00:27:22,060 --> 00:27:25,940 are not super great for serving all of these static assets, 602 00:27:25,940 --> 00:27:27,910 particularly like images. 603 00:27:27,910 --> 00:27:29,860 They're kind of big and a pain to load. 604 00:27:29,860 --> 00:27:32,410 And we're not optimized for it, especially 605 00:27:32,410 --> 00:27:33,850 if we have a high traffic volume. 606 00:27:33,850 --> 00:27:38,410 So it makes a lot more sense to maybe use like an AWS S3 607 00:27:38,410 --> 00:27:40,540 to just have all of your static there. 608 00:27:40,540 --> 00:27:42,760 And then this command actually becomes really useful, 609 00:27:42,760 --> 00:27:45,010 because it means that all the local stuff we have here, 610 00:27:45,010 --> 00:27:47,200 we don't actually put that into our version control. 611 00:27:47,200 --> 00:27:51,400 We just push that onto some sort of remote content delivery network. 612 00:27:51,400 --> 00:27:53,990 And then it gets served from there. 613 00:27:53,990 --> 00:27:55,780 And again, a very cool practice. 614 00:27:55,780 --> 00:27:57,494 It's something that is very useful. 615 00:27:57,494 --> 00:27:59,410 And then this command becomes important to us. 616 00:27:59,410 --> 00:28:02,810 For now, it's actually not too essential that we use it. 617 00:28:02,810 --> 00:28:05,360 But it is there and, I think, worth mentioning. 618 00:28:05,360 --> 00:28:07,300 So yeah, we have this static. 619 00:28:07,300 --> 00:28:10,900 We will later add a web folder underneath static. 620 00:28:10,900 --> 00:28:14,710 And then that will have its own CSS, JavaScript, fonts, images. 621 00:28:14,710 --> 00:28:18,510 I'm generally a person who prefers to do motivated development. 622 00:28:18,510 --> 00:28:21,990 So when I have a need for something, I will then go look it up, figure it out, 623 00:28:21,990 --> 00:28:23,290 and build it. 624 00:28:23,290 --> 00:28:26,304 So I'm not going to put that in here yet, because we don't need it. 625 00:28:26,304 --> 00:28:29,470 I think that it helps keep my code a little bit leaner and a little bit more 626 00:28:29,470 --> 00:28:31,660 streamlined. 627 00:28:31,660 --> 00:28:34,960 But we have the admin interface's static files in here. 628 00:28:34,960 --> 00:28:36,560 And that's good enough for us. 629 00:28:36,560 --> 00:28:37,570 So that's static. 630 00:28:37,570 --> 00:28:41,350 Now, I said we modified settings a little bit. 631 00:28:41,350 --> 00:28:42,370 Thank you. 632 00:28:42,370 --> 00:28:45,070 The IDE I'm using, by the way, is Visual Studio Code. 633 00:28:45,070 --> 00:28:45,872 Love it a lot. 634 00:28:45,872 --> 00:28:47,080 I would definitely recommend. 635 00:28:47,080 --> 00:28:50,260 I also like Atom quite a bit, a personal preference. 636 00:28:50,260 --> 00:28:51,760 There's this cool security key. 637 00:28:51,760 --> 00:28:53,860 Mine is in my version control. 638 00:28:53,860 --> 00:28:56,980 If you would like to go hack this web app on my Heroku here, 639 00:28:56,980 --> 00:28:58,630 you're welcome to. 640 00:28:58,630 --> 00:29:00,190 It won't particularly matter to me. 641 00:29:00,190 --> 00:29:05,230 But the allowed host is what's interesting here. 642 00:29:05,230 --> 00:29:07,420 And so Django actually requires that you tell it 643 00:29:07,420 --> 00:29:09,520 which host it's allowed to be run on. 644 00:29:09,520 --> 00:29:13,300 So 127.0.0.1 is my own local computer. 645 00:29:13,300 --> 00:29:17,770 Well, it's the IP address for local host, which is resolved to 127.0.0.1. 646 00:29:17,770 --> 00:29:19,960 And those two things just allow me to run this app 647 00:29:19,960 --> 00:29:25,150 on my own computer using either the local host or 127.0.0.1 domains 648 00:29:25,150 --> 00:29:26,600 or IPs or addresses. 649 00:29:26,600 --> 00:29:30,470 Now, rangodjango.herokuapp.com is where this is actually live right now. 650 00:29:30,470 --> 00:29:33,160 You're welcome to visit it with your smartphone or your laptop 651 00:29:33,160 --> 00:29:37,210 or your other internet-enabled device. 652 00:29:37,210 --> 00:29:40,570 You can explore a little bit of what the final product of this whole project 653 00:29:40,570 --> 00:29:41,442 looks like. 654 00:29:41,442 --> 00:29:44,150 I don't believe we'll end up actually getting there in this talk. 655 00:29:44,150 --> 00:29:45,525 But there are a bunch of READMEs. 656 00:29:45,525 --> 00:29:47,330 And all the code is online. 657 00:29:47,330 --> 00:29:49,610 It's on that GitHub from the beginning. 658 00:29:49,610 --> 00:29:53,620 And so this allows me to tell Django, only run on these domains. 659 00:29:53,620 --> 00:29:56,480 Any other domain, don't work. 660 00:29:56,480 --> 00:30:00,220 And that's just kind of a quirk of Django, a perk, I would say. 661 00:30:00,220 --> 00:30:03,760 Now, I've added in two apps from the original start. 662 00:30:03,760 --> 00:30:07,480 django_waitress allows us to use that server process Waitress 663 00:30:07,480 --> 00:30:09,784 to actually run and serve Django. 664 00:30:09,784 --> 00:30:11,950 I'm not going to be talking about that one too much. 665 00:30:11,950 --> 00:30:16,390 But we've also added in the main a root project app rango. 666 00:30:16,390 --> 00:30:20,290 And that comes from just this actual subdirectory rango. 667 00:30:20,290 --> 00:30:23,290 And it tells Django to check in rango-- 668 00:30:23,290 --> 00:30:26,140 that's way funnier than I thought it was going to be-- 669 00:30:26,140 --> 00:30:29,410 for actual templates, static assets, things like that. 670 00:30:29,410 --> 00:30:34,840 It tells it to allow looking into that app for certain things. 671 00:30:34,840 --> 00:30:36,560 Web has not been installed yet. 672 00:30:36,560 --> 00:30:39,730 But we just haven't really needed to install it yet. 673 00:30:39,730 --> 00:30:41,431 We will want to install it soon. 674 00:30:41,431 --> 00:30:42,805 I think that's in the next stage. 675 00:30:42,805 --> 00:30:44,846 And we'll want to make sure we take care of that. 676 00:30:44,846 --> 00:30:46,740 Then the last thing at the bottom-- 677 00:30:46,740 --> 00:30:53,050 there we are-- is-- 678 00:30:53,050 --> 00:30:54,970 you'll see I left a comment there that says, 679 00:30:54,970 --> 00:30:56,590 this is not suitable for production. 680 00:30:56,590 --> 00:30:58,120 Don't do this for production. 681 00:30:58,120 --> 00:31:00,110 I repeat, don't do this for production. 682 00:31:00,110 --> 00:31:02,260 This will not help you as far as production goes. 683 00:31:02,260 --> 00:31:04,894 However, it is a very simple way to do some development. 684 00:31:04,894 --> 00:31:07,810 And it's a little bit quicker than the production mechanisms might be. 685 00:31:07,810 --> 00:31:12,550 So what this says is this is the static route, static URL, static dirs, 686 00:31:12,550 --> 00:31:14,427 and project route. 687 00:31:14,427 --> 00:31:16,260 And the reason this is configured the way it 688 00:31:16,260 --> 00:31:17,860 is, in kind of this generalist way-- 689 00:31:17,860 --> 00:31:19,560 I didn't hard code anything-- 690 00:31:19,560 --> 00:31:21,540 well, give or take-- 691 00:31:21,540 --> 00:31:24,000 is because it gets pushed onto Heroku. 692 00:31:24,000 --> 00:31:26,350 And Heroku configures a bunch of stuff for me. 693 00:31:26,350 --> 00:31:29,581 So I don't really want to mess with what they're doing. 694 00:31:29,581 --> 00:31:31,830 So I just say, you know what, wherever this file sits, 695 00:31:31,830 --> 00:31:33,300 that's our project route. 696 00:31:33,300 --> 00:31:35,760 And then I make everything off of that. 697 00:31:35,760 --> 00:31:41,200 Now, static URL just tells Django how to find static assets. 698 00:31:41,200 --> 00:31:44,110 And so whenever a request comes through, we 699 00:31:44,110 --> 00:31:46,710 are going to see how, in urls.py, we actually configured 700 00:31:46,710 --> 00:31:50,400 the URLs a little bit to make it a little bit easier for Django to go, 701 00:31:50,400 --> 00:31:54,390 ho, OK, this is a static asset, go here, as opposed to this 702 00:31:54,390 --> 00:31:58,170 is just a general URL, go there. 703 00:31:58,170 --> 00:32:02,130 And then the static route itself is where on our directory 704 00:32:02,130 --> 00:32:04,230 structure is this located. 705 00:32:04,230 --> 00:32:06,780 If you switch to a production-style version, 706 00:32:06,780 --> 00:32:09,870 then these two things become actually remotely located. 707 00:32:09,870 --> 00:32:11,340 And that's kind of cool. 708 00:32:11,340 --> 00:32:14,190 Static dirs, this also depends on how you're serving things. 709 00:32:14,190 --> 00:32:19,050 Because I'm using kind of just this generalist, Ubuntu-ish, Heroku style 710 00:32:19,050 --> 00:32:22,480 of serving everything, I don't have to worry about this too much. 711 00:32:22,480 --> 00:32:25,492 But actually, this is a list of these URLs paths. 712 00:32:25,492 --> 00:32:27,450 And you can actually list out a couple of them. 713 00:32:27,450 --> 00:32:28,620 And it'll check all of them. 714 00:32:28,620 --> 00:32:30,070 It does check them in order. 715 00:32:30,070 --> 00:32:33,526 And so if you have assets that are named the same thing under the same path 716 00:32:33,526 --> 00:32:36,150 but they're in different directories, be aware that one of them 717 00:32:36,150 --> 00:32:37,800 might get tripped and not the other. 718 00:32:37,800 --> 00:32:38,840 And they'll be in order. 719 00:32:38,840 --> 00:32:42,190 So that is kind of something to keep in mind when you're debugging. 720 00:32:42,190 --> 00:32:46,320 Now, moving onto our urls.py, I left the comments up there at the top. 721 00:32:46,320 --> 00:32:49,130 722 00:32:49,130 --> 00:32:51,050 There are these URL patterns. 723 00:32:51,050 --> 00:32:53,690 So we import from web. 724 00:32:53,690 --> 00:32:57,500 So this basically says, take the web application that we made, 725 00:32:57,500 --> 00:33:00,440 and then take its URLs file, and import that. 726 00:33:00,440 --> 00:33:02,630 We alias it to web_urls. 727 00:33:02,630 --> 00:33:04,640 I think this is generally a decent practice. 728 00:33:04,640 --> 00:33:06,997 But you're welcome to do whatever you'd like for it. 729 00:33:06,997 --> 00:33:08,330 I think it's just very readable. 730 00:33:08,330 --> 00:33:09,900 And then we have urlpatterns. 731 00:33:09,900 --> 00:33:13,650 And this is kind of just my default for the root of the urlpatterns 732 00:33:13,650 --> 00:33:15,920 is I tell it to include all of our static assets, 733 00:33:15,920 --> 00:33:19,100 include admin, and include them in this order. 734 00:33:19,100 --> 00:33:21,980 Now, Django does care a little bit about your urlpatterns 735 00:33:21,980 --> 00:33:27,020 being roughly in order, well, actually exactly in order. 736 00:33:27,020 --> 00:33:29,130 It'll search them in order top to bottom. 737 00:33:29,130 --> 00:33:33,320 So if you have two conflicting paths, only the top one will ever be gotten 738 00:33:33,320 --> 00:33:38,300 to, as in if I had admin/ and admin/, and they went to two different places, 739 00:33:38,300 --> 00:33:40,590 well, we would only get to the top one. 740 00:33:40,590 --> 00:33:42,740 So then we have the static assets here. 741 00:33:42,740 --> 00:33:45,680 And then I just include all my other urlpatterns down here. 742 00:33:45,680 --> 00:33:50,420 Now, I am generally a fan of using just some sort of regular expression 743 00:33:50,420 --> 00:33:54,380 version of a path or generally a path, either/or, to get us 744 00:33:54,380 --> 00:33:58,460 to certain applications underneath. 745 00:33:58,460 --> 00:34:02,960 I like to use this regular expression path with an empty string to match all, 746 00:34:02,960 --> 00:34:07,280 so that any URL that is typed in will get us to that. 747 00:34:07,280 --> 00:34:11,389 Now, include means, actually, this isn't exactly where my URLs are. 748 00:34:11,389 --> 00:34:12,889 Go look at the web URLs. 749 00:34:12,889 --> 00:34:16,230 They're all configured particularly for the web application. 750 00:34:16,230 --> 00:34:20,120 That'll tell you more about how to match things and what to do. 751 00:34:20,120 --> 00:34:22,729 So this is pretty general. 752 00:34:22,729 --> 00:34:25,520 It's not going to tell us too much about how what works underneath. 753 00:34:25,520 --> 00:34:29,029 But it allows us to separate out, our web URLs live in web, 754 00:34:29,029 --> 00:34:34,100 our API URLs live in the API, our email URLs live in email. 755 00:34:34,100 --> 00:34:37,580 And that way, we can separate out functionality a little bit cleaner. 756 00:34:37,580 --> 00:34:40,310 This just tells us what to do, where we go. 757 00:34:40,310 --> 00:34:43,130 You might include some sort of directory here. 758 00:34:43,130 --> 00:34:45,380 I think for web, that should actually be the default. 759 00:34:45,380 --> 00:34:48,920 But it is pretty reasonable to include api/. 760 00:34:48,920 --> 00:34:52,219 And then anytime they go to like api/ blahbity-blah, 761 00:34:52,219 --> 00:34:55,350 they actually get directed to a different part of your application. 762 00:34:55,350 --> 00:34:56,230 Cool. 763 00:34:56,230 --> 00:34:57,960 So we now have that. 764 00:34:57,960 --> 00:35:00,070 urls.py has been examined. 765 00:35:00,070 --> 00:35:04,617 Now we go into web, which is going to have all sorts of other things in it. 766 00:35:04,617 --> 00:35:06,700 It has these migrations which we mentioned before. 767 00:35:06,700 --> 00:35:08,810 They're not going to be super useful to us yet. 768 00:35:08,810 --> 00:35:10,570 But we'll get there. 769 00:35:10,570 --> 00:35:12,010 And then we have admin.py. 770 00:35:12,010 --> 00:35:13,900 Again, not going to matter too much to us 771 00:35:13,900 --> 00:35:15,610 right now or probably throughout this. 772 00:35:15,610 --> 00:35:17,741 But it is a very useful thing to understand. 773 00:35:17,741 --> 00:35:19,990 This allows you to take all the models that you build, 774 00:35:19,990 --> 00:35:22,090 all of those beautiful classes in Python, 775 00:35:22,090 --> 00:35:24,490 and put them onto an admin interface that 776 00:35:24,490 --> 00:35:27,220 is usable by the general user of your site 777 00:35:27,220 --> 00:35:29,990 who doesn't necessarily need to understand a whole lot of Python. 778 00:35:29,990 --> 00:35:33,160 It also lets you create instances of models and stuff like that. 779 00:35:33,160 --> 00:35:34,142 You have apps.py. 780 00:35:34,142 --> 00:35:36,600 We're not going to talk too much about apps.py or tests.py, 781 00:35:36,600 --> 00:35:37,699 though they are useful. 782 00:35:37,699 --> 00:35:39,490 And then you have models.py, which is where 783 00:35:39,490 --> 00:35:43,060 we're going to actually create all of our database structures and interfaces 784 00:35:43,060 --> 00:35:44,020 there. 785 00:35:44,020 --> 00:35:45,610 We'll get there in a little while. 786 00:35:45,610 --> 00:35:50,257 We have urls.py, which is very generally built. It does very little right now. 787 00:35:50,257 --> 00:35:52,840 But we are going to point out that it imports all of the views 788 00:35:52,840 --> 00:35:54,610 from this application. 789 00:35:54,610 --> 00:35:57,430 And then it does that same kind of catch-all pattern matching 790 00:35:57,430 --> 00:36:00,190 to just say, hey, anything that comes through here, 791 00:36:00,190 --> 00:36:02,980 throw that to this, which is index. 792 00:36:02,980 --> 00:36:06,850 Now, index is something that I assume I imported from web.views. 793 00:36:06,850 --> 00:36:09,730 If I was a better developer, I probably would have explicitly stated 794 00:36:09,730 --> 00:36:11,860 that index was imported from web.views. 795 00:36:11,860 --> 00:36:13,440 I am, however, a lazy developer. 796 00:36:13,440 --> 00:36:15,190 This is not necessarily the best practice. 797 00:36:15,190 --> 00:36:18,230 It's not clear to me immediately where index came from. 798 00:36:18,230 --> 00:36:21,550 However, I think that it's tolerable for now. 799 00:36:21,550 --> 00:36:23,480 If you wanted to be a much better developer, 800 00:36:23,480 --> 00:36:26,800 you would be very clear as to where exactly index came from, otherwise 801 00:36:26,800 --> 00:36:29,570 it seems kind of magical. 802 00:36:29,570 --> 00:36:32,680 And then, speaking of where index came from, we'll look at views. 803 00:36:32,680 --> 00:36:37,330 And within views.py, we actually have access to index. 804 00:36:37,330 --> 00:36:39,696 So if you're confused about how views work, 805 00:36:39,696 --> 00:36:42,820 they're actually something very similar to something you probably hopefully 806 00:36:42,820 --> 00:36:45,220 already understand, which is Python functions. 807 00:36:45,220 --> 00:36:47,567 And all they take in, at least by default-- 808 00:36:47,567 --> 00:36:49,150 and they can be expanded quite a bit-- 809 00:36:49,150 --> 00:36:53,180 is this request objects, so that's your HTTP request, it's either get, post. 810 00:36:53,180 --> 00:36:57,070 Oh, there's a bunch of other ones like put, patch, and a few other ones. 811 00:36:57,070 --> 00:36:59,200 We'll talk mostly about get and post. 812 00:36:59,200 --> 00:37:04,540 And then it returns this very basic HTTP response which just takes in some HTML 813 00:37:04,540 --> 00:37:07,184 as a string and puts that back out to the user. 814 00:37:07,184 --> 00:37:09,850 And this is independent of whether it's a get, post, put, patch. 815 00:37:09,850 --> 00:37:11,080 It doesn't matter. 816 00:37:11,080 --> 00:37:14,550 It will do this every single time it receives a request. 817 00:37:14,550 --> 00:37:19,000 And I imported HTTP response from Django's HTTP submodule. 818 00:37:19,000 --> 00:37:21,520 That's generally, I think, a decent way to start. 819 00:37:21,520 --> 00:37:24,220 It lets me just know that I got things working correctly. 820 00:37:24,220 --> 00:37:27,110 And speaking of getting things working correctly, 821 00:37:27,110 --> 00:37:30,790 let's go ahead and verify that that's actually true. 822 00:37:30,790 --> 00:37:33,460 We'll run the same command that we ran before. 823 00:37:33,460 --> 00:37:36,610 It's going to print out the same error about unapplied migrations. 824 00:37:36,610 --> 00:37:37,152 It's correct. 825 00:37:37,152 --> 00:37:38,609 We have not applied our migrations. 826 00:37:38,609 --> 00:37:40,420 We don't really have a whole lot to apply. 827 00:37:40,420 --> 00:37:44,350 And when I reload the page, I get to Hello comma world, exclamation point. 828 00:37:44,350 --> 00:37:45,190 Hello, world! 829 00:37:45,190 --> 00:37:46,390 And so I have gotten here. 830 00:37:46,390 --> 00:37:47,560 It's very ugly. 831 00:37:47,560 --> 00:37:49,000 It's mostly white space. 832 00:37:49,000 --> 00:37:52,730 But we do have that in the upper left-hand corner. 833 00:37:52,730 --> 00:37:54,790 And that should make sense to us, because we 834 00:37:54,790 --> 00:37:58,330 created a view that controlled any sort of response 835 00:37:58,330 --> 00:38:00,850 so that after I put in the URL into my browser 836 00:38:00,850 --> 00:38:07,720 and it sends a request to our basic 127.0.0.1:8.8.8.8, then Django said, 837 00:38:07,720 --> 00:38:12,100 OK, well, we should go and match that to whatever matches first here. 838 00:38:12,100 --> 00:38:13,840 It doesn't match admin at least. 839 00:38:13,840 --> 00:38:15,670 It doesn't match anything in static. 840 00:38:15,670 --> 00:38:18,450 But it does match the everything wildcard. 841 00:38:18,450 --> 00:38:20,590 And that says, go into weburls. 842 00:38:20,590 --> 00:38:22,300 OK, so let's go to weburls. 843 00:38:22,300 --> 00:38:26,846 And that says, match anything, then take that request, and hand it off to index. 844 00:38:26,846 --> 00:38:27,970 And that's in our views.py. 845 00:38:27,970 --> 00:38:28,840 So we look at index. 846 00:38:28,840 --> 00:38:30,820 And we say, OK, we take in some request. 847 00:38:30,820 --> 00:38:32,800 That was the HTTP request that we got. 848 00:38:32,800 --> 00:38:37,210 And regardless of what it was, just return this open-handed hello world 849 00:38:37,210 --> 00:38:39,650 using the first type of header. 850 00:38:39,650 --> 00:38:40,949 That was a mouthful. 851 00:38:40,949 --> 00:38:41,990 And that's what happened. 852 00:38:41,990 --> 00:38:43,720 So I am very glad. 853 00:38:43,720 --> 00:38:46,220 I don't know if you're very glad, but hopefully you are too. 854 00:38:46,220 --> 00:38:49,511 I'm particularly glad that worked beautifully. 855 00:38:49,511 --> 00:38:54,390 And so yes, that actually is what ended up going on underneath the hood. 856 00:38:54,390 --> 00:38:59,240 And we roughly understand a lot about how Django works generally. 857 00:38:59,240 --> 00:39:02,330 Now, I say that the URLs can be configured to be kind of magical. 858 00:39:02,330 --> 00:39:05,267 And we're going to see that in a hot second. 859 00:39:05,267 --> 00:39:07,850 That is kind of a weird expression in English, just as an FYI. 860 00:39:07,850 --> 00:39:11,980 So we're going to go up into stage 2. 861 00:39:11,980 --> 00:39:14,440 Cool, we have very similar things in stage 2. 862 00:39:14,440 --> 00:39:15,700 We haven't modified much. 863 00:39:15,700 --> 00:39:18,079 I tried to make these pretty reasonable stages 864 00:39:18,079 --> 00:39:20,120 but we're going to actually write some HTML here. 865 00:39:20,120 --> 00:39:23,920 And so the way HTML and templating in general works in Django 866 00:39:23,920 --> 00:39:26,560 is it uses Django's built-in templating engine. 867 00:39:26,560 --> 00:39:29,020 You can actually modify the engines underneath. 868 00:39:29,020 --> 00:39:31,210 Django's settings.py is extremely versatile. 869 00:39:31,210 --> 00:39:34,030 It allows you to configure all sorts of environment variables 870 00:39:34,030 --> 00:39:36,540 and just variables in general for Django to be using. 871 00:39:36,540 --> 00:39:40,370 And anything in Django, any subapp, any subfile 872 00:39:40,370 --> 00:39:42,370 can actually access all of the settings configs. 873 00:39:42,370 --> 00:39:43,661 And we'll see that in a second. 874 00:39:43,661 --> 00:39:49,360 Actually, we saw that in rango's urls.py. 875 00:39:49,360 --> 00:39:51,680 We import settings up here at the top. 876 00:39:51,680 --> 00:39:54,520 And you can access any of the conflict variables in settings 877 00:39:54,520 --> 00:39:58,900 with settings.configvariablename, just something useful to know. 878 00:39:58,900 --> 00:40:01,780 So we didn't really change this urls.py very much. 879 00:40:01,780 --> 00:40:04,270 We don't need to in order to add templating. 880 00:40:04,270 --> 00:40:06,190 Static has not really changed a whole lot. 881 00:40:06,190 --> 00:40:09,250 Nothing in rango, the base app, has really changed. 882 00:40:09,250 --> 00:40:12,430 However, in web, we have modified a little bit of what's going on. 883 00:40:12,430 --> 00:40:14,320 Now, we have built some templates. 884 00:40:14,320 --> 00:40:15,970 In fact, we've built two. 885 00:40:15,970 --> 00:40:18,549 They're index.html and posts.html. 886 00:40:18,549 --> 00:40:21,340 We're building a randomized blog, because I thought that was funny, 887 00:40:21,340 --> 00:40:22,720 and it made for a cool name. 888 00:40:22,720 --> 00:40:26,530 So it makes sense that we would have some home page or index and some posts 889 00:40:26,530 --> 00:40:29,800 page that lets us deliver our posts. 890 00:40:29,800 --> 00:40:32,870 Now, I wanted to be a little bit contrived in classic CS style. 891 00:40:32,870 --> 00:40:35,950 So this is kind of a derpy page. 892 00:40:35,950 --> 00:40:37,340 It's got very little in it. 893 00:40:37,340 --> 00:40:39,880 In its body, I've got container fluid. 894 00:40:39,880 --> 00:40:40,840 That's from Bootstrap. 895 00:40:40,840 --> 00:40:44,807 But I basically just display "Hello, this is rango, the random Django blog." 896 00:40:44,807 --> 00:40:47,140 And then there's a bunch of other stuff that's included. 897 00:40:47,140 --> 00:40:48,160 This is just-- 898 00:40:48,160 --> 00:40:51,490 I basically just copied it from Bootstrap's documentation. 899 00:40:51,490 --> 00:40:53,660 I like Bootstrap quite a bit. 900 00:40:53,660 --> 00:40:56,735 I think that generally, you should build a web app from complete scratch 901 00:40:56,735 --> 00:40:59,110 before you actually start using some of those frameworks. 902 00:40:59,110 --> 00:41:01,550 It helps give you a better intuition for what's going on. 903 00:41:01,550 --> 00:41:03,070 But there's some other tags up here that we're not 904 00:41:03,070 --> 00:41:04,480 going to worry too much about. 905 00:41:04,480 --> 00:41:08,800 And then I copied and pasted which, according to see CS51 here, 906 00:41:08,800 --> 00:41:11,020 you should never ever do in code. 907 00:41:11,020 --> 00:41:14,500 I think it's like a never, ever with a star. 908 00:41:14,500 --> 00:41:16,380 Generally, try not to. 909 00:41:16,380 --> 00:41:19,141 And as a good rule of thumb, if you're copying and pasting code, 910 00:41:19,141 --> 00:41:21,640 you could probably abstract something out or build something 911 00:41:21,640 --> 00:41:22,714 a little bit better. 912 00:41:22,714 --> 00:41:25,630 It's almost like I'm foreshadowing what we're going to do in a second. 913 00:41:25,630 --> 00:41:28,570 But I copied and pasted this code. 914 00:41:28,570 --> 00:41:31,420 And so we have basically the same page, except in its body, 915 00:41:31,420 --> 00:41:36,370 it displays whatever the content of that page is, a rango post, 916 00:41:36,370 --> 00:41:38,620 because rango Django, random Django. 917 00:41:38,620 --> 00:41:41,290 But in here, we have a paragraph tag. 918 00:41:41,290 --> 00:41:44,980 And we have this curly brace curly brace, variable name, 919 00:41:44,980 --> 00:41:46,320 curly brace curly brace. 920 00:41:46,320 --> 00:41:48,820 And I say variable name like that because it's not intuitive 921 00:41:48,820 --> 00:41:50,500 that that is a variable name. 922 00:41:50,500 --> 00:41:52,700 But this is templating syntax. 923 00:41:52,700 --> 00:41:55,750 It's the first of a little bit that we will see. 924 00:41:55,750 --> 00:41:57,370 It's the only one on this page. 925 00:41:57,370 --> 00:42:03,190 And what it says is that somewhere in this nebulous Django templating engine, 926 00:42:03,190 --> 00:42:05,780 post_content has been defined. 927 00:42:05,780 --> 00:42:08,980 If it hasn't, Django just goes, oops, and just runs it, 928 00:42:08,980 --> 00:42:12,310 because it's a little bit weird to display some sort of error. 929 00:42:12,310 --> 00:42:15,310 Django actually does have templating errors that can occur. 930 00:42:15,310 --> 00:42:16,570 And those are great. 931 00:42:16,570 --> 00:42:19,810 The more errors that you can catch and the more modular and atomic they 932 00:42:19,810 --> 00:42:22,060 are, the better, because then I can know, oh, 933 00:42:22,060 --> 00:42:24,040 exactly what I'm trying to fix. 934 00:42:24,040 --> 00:42:26,140 The generalist catch-all, which we actually 935 00:42:26,140 --> 00:42:31,450 do do later in the views.py where we do try except:, 936 00:42:31,450 --> 00:42:34,030 there's no exception in particular that is caught. 937 00:42:34,030 --> 00:42:34,696 That's awful. 938 00:42:34,696 --> 00:42:36,820 How are you going to know what exception was there? 939 00:42:36,820 --> 00:42:38,167 How do you know what went wrong? 940 00:42:38,167 --> 00:42:40,750 It's really good for making sure that your application doesn't 941 00:42:40,750 --> 00:42:41,610 stumble and fall. 942 00:42:41,610 --> 00:42:43,780 It just kind of stumbles, looks around, and hopes 943 00:42:43,780 --> 00:42:45,430 no one noticed and then keeps going. 944 00:42:45,430 --> 00:42:48,850 But generally, you want to know, when you're developing, 945 00:42:48,850 --> 00:42:52,300 what exactly went wrong as precisely as possible. 946 00:42:52,300 --> 00:42:54,310 So templating errors are really cool. 947 00:42:54,310 --> 00:42:56,530 And the reason that those can occur in Django 948 00:42:56,530 --> 00:43:00,700 is because templates get rendered before they ever get sent to the user. 949 00:43:00,700 --> 00:43:03,160 So this will never be visible to the user. 950 00:43:03,160 --> 00:43:06,070 This will get replaced with whatever it is as a variable. 951 00:43:06,070 --> 00:43:09,010 And you use this curly brace-curly brace to indicate 952 00:43:09,010 --> 00:43:10,670 that I want this to be in there. 953 00:43:10,670 --> 00:43:13,210 It's generally used for some sort of content. 954 00:43:13,210 --> 00:43:15,820 And so this should be probably some sort of string, 955 00:43:15,820 --> 00:43:18,640 because it's going into a P tag or paragraph tag. 956 00:43:18,640 --> 00:43:23,860 And so hopefully, knock on wood, the developer who built this-- that's me-- 957 00:43:23,860 --> 00:43:26,310 made sure that this was some sort of string. 958 00:43:26,310 --> 00:43:29,560 And you might be wondering, cool, cool, where? 959 00:43:29,560 --> 00:43:30,834 Where was this defined? 960 00:43:30,834 --> 00:43:32,000 And that's a great question. 961 00:43:32,000 --> 00:43:33,083 I'm really glad you asked. 962 00:43:33,083 --> 00:43:36,540 So if you go into your views.py, we've modified that too. 963 00:43:36,540 --> 00:43:37,300 Go, us! 964 00:43:37,300 --> 00:43:39,760 And so we actually have this same index. 965 00:43:39,760 --> 00:43:42,100 But we have, also, posts. 966 00:43:42,100 --> 00:43:44,020 And you might be going, you said the same. 967 00:43:44,020 --> 00:43:44,777 You lied. 968 00:43:44,777 --> 00:43:45,610 That's not the same. 969 00:43:45,610 --> 00:43:49,780 This is no longer an HTTP response, at least not explicitly. 970 00:43:49,780 --> 00:43:51,740 It's a render. 971 00:43:51,740 --> 00:43:55,090 And then we have passed than and the request itself as well as 972 00:43:55,090 --> 00:43:56,980 the name of one of our templates. 973 00:43:56,980 --> 00:44:00,900 Now, there's a lot that had to change in Django to get this to happen. 974 00:44:00,900 --> 00:44:05,600 But let's say that we went and we return render of request index.html. 975 00:44:05,600 --> 00:44:08,360 And then we do this weird context as a dictionary. 976 00:44:08,360 --> 00:44:12,020 And then we say context at post_content-- 977 00:44:12,020 --> 00:44:13,610 hey, that looks familiar-- 978 00:44:13,610 --> 00:44:17,137 is defined as this long string of lorem ipsum. 979 00:44:17,137 --> 00:44:18,720 I pulled that from an API, by the way. 980 00:44:18,720 --> 00:44:19,700 I did not build it myself. 981 00:44:19,700 --> 00:44:21,056 I also did not manually type it. 982 00:44:21,056 --> 00:44:22,430 I can't type nearly that quickly. 983 00:44:22,430 --> 00:44:24,170 I'd still be typing it. 984 00:44:24,170 --> 00:44:27,050 And so then we have return the rendering of-- 985 00:44:27,050 --> 00:44:29,360 this is very similar up to this point-- 986 00:44:29,360 --> 00:44:34,220 of the return above where we render-- this is the request that was passed in. 987 00:44:34,220 --> 00:44:37,501 It lets us set session IDs and variables and caches and cookies and things. 988 00:44:37,501 --> 00:44:40,250 And then this is where we're actually going, like what web page do 989 00:44:40,250 --> 00:44:41,800 we actually return to the user. 990 00:44:41,800 --> 00:44:47,910 And then this, context=context is a very convenient way that Django passes, 991 00:44:47,910 --> 00:44:49,580 things into the templating engine. 992 00:44:49,580 --> 00:44:54,200 So I've defined, as one of the keys of the context dictionary, post_content. 993 00:44:54,200 --> 00:44:56,420 And its value is this string. 994 00:44:56,420 --> 00:44:59,540 And you'll notice that we have guaranteed, kind of by hard coding, 995 00:44:59,540 --> 00:45:02,070 that this will be a string. 996 00:45:02,070 --> 00:45:06,620 And so by doing that, we now have access to this post_content variable 997 00:45:06,620 --> 00:45:08,510 within our Django templating engine. 998 00:45:08,510 --> 00:45:10,205 And hopefully we're very happy. 999 00:45:10,205 --> 00:45:12,080 However, if you were to just do these things, 1000 00:45:12,080 --> 00:45:13,580 it still would not entirely work. 1001 00:45:13,580 --> 00:45:16,160 We have to make sure that Django knows how to get to posts. 1002 00:45:16,160 --> 00:45:19,830 I still use this general catch-all to get us to index, or our home page. 1003 00:45:19,830 --> 00:45:27,930 However, if you pass in posts now, you actually go to the posts view. 1004 00:45:27,930 --> 00:45:29,390 I'm still using import*. 1005 00:45:29,390 --> 00:45:33,380 However, it would be equivalent and probably better coding to do 1006 00:45:33,380 --> 00:45:35,780 posts,index. 1007 00:45:35,780 --> 00:45:37,010 That's not what I wanted. 1008 00:45:37,010 --> 00:45:38,050 Cool. 1009 00:45:38,050 --> 00:45:40,160 And then you might be going, excellent. 1010 00:45:40,160 --> 00:45:41,750 This will now work perfectly. 1011 00:45:41,750 --> 00:45:45,440 And you'd be almost correct, except it won't, because templates is not 1012 00:45:45,440 --> 00:45:47,880 something we explicitly tell Django to go look for, 1013 00:45:47,880 --> 00:45:50,870 at least a we might not have noticed where we told it to do that. 1014 00:45:50,870 --> 00:45:54,110 We told it that in settings.py in our root app. 1015 00:45:54,110 --> 00:45:56,930 But we actually never installed web. 1016 00:45:56,930 --> 00:45:59,960 So we're going to want to go up into rango, under settings.py. 1017 00:45:59,960 --> 00:46:01,850 And we're going to look into installed apps. 1018 00:46:01,850 --> 00:46:04,110 And you'll notice web is now there. 1019 00:46:04,110 --> 00:46:06,740 And the reason for that is because Django 1020 00:46:06,740 --> 00:46:12,200 will check each of these things, each of these apps for a templates directory. 1021 00:46:12,200 --> 00:46:15,440 And it'll say, hey, if you have a templates directory, 1022 00:46:15,440 --> 00:46:17,330 kick those into the things that we actually 1023 00:46:17,330 --> 00:46:19,240 check in order to render templates. 1024 00:46:19,240 --> 00:46:23,150 So when I say return render a request and some template name, 1025 00:46:23,150 --> 00:46:26,180 it's going to look in these ones' templates directories. 1026 00:46:26,180 --> 00:46:27,892 And then we'll go, oh, bummer. 1027 00:46:27,892 --> 00:46:29,600 And it's very common for people to forget 1028 00:46:29,600 --> 00:46:32,510 to do this, yours truly included, even now. 1029 00:46:32,510 --> 00:46:34,130 And then they go, why. 1030 00:46:34,130 --> 00:46:35,150 I made this template. 1031 00:46:35,150 --> 00:46:35,749 Where is it? 1032 00:46:35,749 --> 00:46:36,540 I don't understand. 1033 00:46:36,540 --> 00:46:38,336 Why is Django not working? 1034 00:46:38,336 --> 00:46:40,460 It's the equivalent of yelling at the compiler when 1035 00:46:40,460 --> 00:46:42,890 you're doing C development. 1036 00:46:42,890 --> 00:46:45,020 It's not my fault. It's your fault. And then you're 1037 00:46:45,020 --> 00:46:46,311 yelling at an inanimate object. 1038 00:46:46,311 --> 00:46:47,600 And people think you're weird. 1039 00:46:47,600 --> 00:46:48,930 Welcome to computer science. 1040 00:46:48,930 --> 00:46:52,181 So installing this saves you a lot of trouble and frustration. 1041 00:46:52,181 --> 00:46:53,930 And it makes you look a little less weird. 1042 00:46:53,930 --> 00:46:56,180 So just remember to do it. 1043 00:46:56,180 --> 00:47:00,110 And now everything is all wired together correctly. 1044 00:47:00,110 --> 00:47:04,010 So we might go, OK, excellent manage.py. 1045 00:47:04,010 --> 00:47:06,509 And this command should become second nature to you. 1046 00:47:06,509 --> 00:47:09,050 I'm actually going to stop manually typing it out after this. 1047 00:47:09,050 --> 00:47:13,260 Oh, no, this is why you stop manually typing that out. 1048 00:47:13,260 --> 00:47:14,234 There we go. 1049 00:47:14,234 --> 00:47:16,650 And you'll notice, if we open up that output a little bit, 1050 00:47:16,650 --> 00:47:19,910 I still have 15 unapplied migrations, unsurprising. 1051 00:47:19,910 --> 00:47:22,080 I kind of am deliberately ignoring that. 1052 00:47:22,080 --> 00:47:23,640 And we might re-render this. 1053 00:47:23,640 --> 00:47:27,400 It'll take a little bit longer, because it's actually rendering something now. 1054 00:47:27,400 --> 00:47:30,626 And it's doing its job a little bit better. 1055 00:47:30,626 --> 00:47:32,750 Yeah, the other thing about live demos, anytime 1056 00:47:32,750 --> 00:47:35,150 you're doing real coding or just anything 1057 00:47:35,150 --> 00:47:37,290 that depends on some sort of time constraint 1058 00:47:37,290 --> 00:47:39,290 live, it's kind of like when you need a printer. 1059 00:47:39,290 --> 00:47:40,940 It'll never work. 1060 00:47:40,940 --> 00:47:43,190 The internet stops working just perpetually. 1061 00:47:43,190 --> 00:47:45,950 And this is a locally hosted thing, and it still 1062 00:47:45,950 --> 00:47:47,690 stops working, which is ridiculous. 1063 00:47:47,690 --> 00:47:49,910 So you'll notice, in even smaller text, because I 1064 00:47:49,910 --> 00:47:51,701 thought you guys needed a little bit of eye 1065 00:47:51,701 --> 00:47:55,790 exercise, you'll see, "Hello, this is rango, the random Django blog." 1066 00:47:55,790 --> 00:47:56,780 I think I'm funny. 1067 00:47:56,780 --> 00:48:01,010 And nothing else, so it's ugly as heck would be a way to say that. 1068 00:48:01,010 --> 00:48:04,190 But if we going to posts, this should change, fingers crossed. 1069 00:48:04,190 --> 00:48:07,400 And we get there, and this is a rango post in much bigger text. 1070 00:48:07,400 --> 00:48:12,590 And then you get the cool lorem ipsum blah, blah, blah there. 1071 00:48:12,590 --> 00:48:14,999 And that is exactly what we hopefully expected, 1072 00:48:14,999 --> 00:48:17,540 because we didn't do any real fancy formatting with Bootstrap 1073 00:48:17,540 --> 00:48:18,630 or anything of the sort. 1074 00:48:18,630 --> 00:48:21,020 So we get this. 1075 00:48:21,020 --> 00:48:26,510 And so we now have successfully looped up some of what Django actually does, 1076 00:48:26,510 --> 00:48:29,780 which is fantastic for us. 1077 00:48:29,780 --> 00:48:33,590 Now that we've gotten through there, we're going to go through stage 3. 1078 00:48:33,590 --> 00:48:36,932 And you'll notice, hopefully, that as we kind of get going, 1079 00:48:36,932 --> 00:48:39,890 we'll get going a little bit faster and faster, because things will not 1080 00:48:39,890 --> 00:48:40,635 really-- 1081 00:48:40,635 --> 00:48:42,260 we won't have to change as many places. 1082 00:48:42,260 --> 00:48:44,059 And we'll just be changing a little bit. 1083 00:48:44,059 --> 00:48:46,850 Also, you guys will have a very good intuition for what's going on. 1084 00:48:46,850 --> 00:48:49,391 Or y'all will have a very good intuition for what's going on. 1085 00:48:49,391 --> 00:48:52,610 And we won't have to explain nearly as much of what exactly is changing. 1086 00:48:52,610 --> 00:49:00,000 Now, in stage 3, we've said, OK, it was really annoying to re-copy and paste. 1087 00:49:00,000 --> 00:49:02,867 I alluded to this at the very beginning of the last stage. 1088 00:49:02,867 --> 00:49:04,950 I said, you know what, we actually should probably 1089 00:49:04,950 --> 00:49:06,360 make this a little bit more extensible. 1090 00:49:06,360 --> 00:49:07,860 Our developers are all in a mess. 1091 00:49:07,860 --> 00:49:12,300 They all keep complaining that I change code, and then Sally changes code, 1092 00:49:12,300 --> 00:49:15,510 and then Bob changes code, and no one knows who changed what or when 1093 00:49:15,510 --> 00:49:16,260 or who's on first. 1094 00:49:16,260 --> 00:49:18,130 So it's really frustrating. 1095 00:49:18,130 --> 00:49:18,930 So we do this. 1096 00:49:18,930 --> 00:49:20,580 Now, there's all these curly braces. 1097 00:49:20,580 --> 00:49:22,704 And you're like, dude, you just changed everything. 1098 00:49:22,704 --> 00:49:23,580 Nothing is the same. 1099 00:49:23,580 --> 00:49:24,810 What the heck? 1100 00:49:24,810 --> 00:49:26,250 And you'd be roughly right. 1101 00:49:26,250 --> 00:49:28,840 So what we've done is actually quite a bit. 1102 00:49:28,840 --> 00:49:32,400 We've said, hey, there's this curly brace percent sign, 1103 00:49:32,400 --> 00:49:34,260 not a double curly brace anymore. 1104 00:49:34,260 --> 00:49:38,040 And what that means is this is like Django templating run a function. 1105 00:49:38,040 --> 00:49:39,660 So we run the extends function. 1106 00:49:39,660 --> 00:49:42,720 That can only be done once at the top of the template. 1107 00:49:42,720 --> 00:49:44,400 You can only extend one other template. 1108 00:49:44,400 --> 00:49:46,660 But you can chain a bunch of extends. 1109 00:49:46,660 --> 00:49:48,840 And so we extend base.html. 1110 00:49:48,840 --> 00:49:51,060 And you're like, Nick, we didn't write a base.html. 1111 00:49:51,060 --> 00:49:52,200 And I'm like, you're right. 1112 00:49:52,200 --> 00:49:53,820 We're going to go point out what that is. 1113 00:49:53,820 --> 00:49:56,430 However, you might intuit that that is going to just kind of, 1114 00:49:56,430 --> 00:49:59,310 do a general layout for what's going on. 1115 00:49:59,310 --> 00:50:00,690 Then we do this load static. 1116 00:50:00,690 --> 00:50:02,402 And you're like dude what the-- 1117 00:50:02,402 --> 00:50:03,360 where'd that come from? 1118 00:50:03,360 --> 00:50:04,530 And I would agree. 1119 00:50:04,530 --> 00:50:05,610 It's a little confusing. 1120 00:50:05,610 --> 00:50:07,880 But this is alluding to our static files. 1121 00:50:07,880 --> 00:50:14,040 It's generally a good thing to include if you're going to use your own custom 1122 00:50:14,040 --> 00:50:15,820 static, which is what we did here. 1123 00:50:15,820 --> 00:50:17,040 Now, there's these blocks. 1124 00:50:17,040 --> 00:50:18,748 And we'll see what those are in a second, 1125 00:50:18,748 --> 00:50:22,460 because they're actually defined more similarly or more understandably 1126 00:50:22,460 --> 00:50:23,910 in base.html. 1127 00:50:23,910 --> 00:50:25,612 We have a block title. 1128 00:50:25,612 --> 00:50:27,820 Hopefully, intuitively, that's the title of the page. 1129 00:50:27,820 --> 00:50:29,310 This is home, because it's index. 1130 00:50:29,310 --> 00:50:30,420 This is a block CSS. 1131 00:50:30,420 --> 00:50:33,390 It contains all of our custom CSS that we don't necessarily 1132 00:50:33,390 --> 00:50:35,670 want to import to every single page but we 1133 00:50:35,670 --> 00:50:37,540 want to import it whenever we need to. 1134 00:50:37,540 --> 00:50:39,520 So it gets included here. 1135 00:50:39,520 --> 00:50:41,910 And then this is just our custom style sheet. 1136 00:50:41,910 --> 00:50:45,570 And since it's locally hosted, it's defined by our own static. 1137 00:50:45,570 --> 00:50:49,350 We actually use this static tag which will regenerate the URL based 1138 00:50:49,350 --> 00:50:51,240 on where our static assets live, which makes 1139 00:50:51,240 --> 00:50:55,907 static assets being locally hosted versus a CDN hosted very plug-and-play. 1140 00:50:55,907 --> 00:50:57,240 You just swap out the back ends. 1141 00:50:57,240 --> 00:51:00,210 And no one else notices. 1142 00:51:00,210 --> 00:51:03,010 And then we list out it's relative path. 1143 00:51:03,010 --> 00:51:06,040 And we have block body, which is the body. 1144 00:51:06,040 --> 00:51:09,480 And it has all the same content as before with a little bit more styling 1145 00:51:09,480 --> 00:51:11,390 due to bootstrap. 1146 00:51:11,390 --> 00:51:13,890 I don't like things looking too ugly. 1147 00:51:13,890 --> 00:51:18,092 And so I included some cuter snippets here, whatever. 1148 00:51:18,092 --> 00:51:20,550 And then we look in posts, and it's something very similar. 1149 00:51:20,550 --> 00:51:22,716 But you'll notice, it's a lot less code them before. 1150 00:51:22,716 --> 00:51:25,830 We're at around 20 lines for roughly the same content, 1151 00:51:25,830 --> 00:51:28,050 even though it'll look a little bit prettier. 1152 00:51:28,050 --> 00:51:30,187 And so you'll see the post content is still here. 1153 00:51:30,187 --> 00:51:31,770 This is under body, which makes sense. 1154 00:51:31,770 --> 00:51:34,722 We include the same style sheet. 1155 00:51:34,722 --> 00:51:36,180 And then we have a different title. 1156 00:51:36,180 --> 00:51:37,230 This is posts. 1157 00:51:37,230 --> 00:51:39,670 And we load static and extend base.html. 1158 00:51:39,670 --> 00:51:41,919 I don't know why I went through that in reverse order. 1159 00:51:41,919 --> 00:51:44,940 If that was confusing, just watch the YouTube video in reverse. 1160 00:51:44,940 --> 00:51:47,010 And then we're going to go look up at rango. 1161 00:51:47,010 --> 00:51:50,877 And notice, it also has a templates directory now. 1162 00:51:50,877 --> 00:51:52,710 And when we go into that, there's base.html. 1163 00:51:52,710 --> 00:51:54,960 And you're like, oh, thank god, that's where it went. 1164 00:51:54,960 --> 00:51:59,850 And this has all of our standard doctype, html, charset, all this. 1165 00:51:59,850 --> 00:52:02,530 And then you'll notice these empty blocks. 1166 00:52:02,530 --> 00:52:04,540 This is a CSS block that has nothing in it. 1167 00:52:04,540 --> 00:52:06,150 And then you'll go, oh, of course. 1168 00:52:06,150 --> 00:52:08,560 When we did our index.html and our post.html, 1169 00:52:08,560 --> 00:52:12,100 we wrapped it in the same block CSS and block, but we put stuff in there. 1170 00:52:12,100 --> 00:52:13,530 We put stuff in the middle here. 1171 00:52:13,530 --> 00:52:17,190 And that actually just gets copy-pasted onto this. 1172 00:52:17,190 --> 00:52:18,090 Same thing for title. 1173 00:52:18,090 --> 00:52:22,210 It does the exact same functionality, except this is in the title tag. 1174 00:52:22,210 --> 00:52:23,400 And then I added a nav bar. 1175 00:52:23,400 --> 00:52:25,127 Don't worry too much about what that is. 1176 00:52:25,127 --> 00:52:26,710 I just copy and pasted from Bootstrap. 1177 00:52:26,710 --> 00:52:27,390 Bootstrap's great. 1178 00:52:27,390 --> 00:52:29,098 They do all sorts of cool coding for you. 1179 00:52:29,098 --> 00:52:30,810 Just copy and paste it in. 1180 00:52:30,810 --> 00:52:32,970 And then I added the block body here. 1181 00:52:32,970 --> 00:52:34,540 And we added this JavaScript block. 1182 00:52:34,540 --> 00:52:35,373 We don't use it yet. 1183 00:52:35,373 --> 00:52:38,340 But it's a decent practice for not including all of your JavaScript 1184 00:52:38,340 --> 00:52:40,230 all the time at every page. 1185 00:52:40,230 --> 00:52:41,700 It can be very heavy to include. 1186 00:52:41,700 --> 00:52:44,400 And by heavy, I mean it takes a while over a network. 1187 00:52:44,400 --> 00:52:47,640 So again, I'm going to stop typing that out by hand. 1188 00:52:47,640 --> 00:52:49,230 We're going to again run run server. 1189 00:52:49,230 --> 00:52:51,124 We again, have unapplied migrations. 1190 00:52:51,124 --> 00:52:52,790 None of that should be counterintuitive. 1191 00:52:52,790 --> 00:52:54,480 What you'll note is that it looks a little bit prettier now. 1192 00:52:54,480 --> 00:52:55,620 We're still on posts. 1193 00:52:55,620 --> 00:52:57,900 We have a nav bar, which is great. 1194 00:52:57,900 --> 00:53:00,360 Rango, Random Django, Rango. 1195 00:53:00,360 --> 00:53:02,610 And then we have a jumbotron going on. 1196 00:53:02,610 --> 00:53:03,870 That's a bootstrap thing. 1197 00:53:03,870 --> 00:53:05,670 And we have cooler formatting. 1198 00:53:05,670 --> 00:53:08,232 It looks a little bit prettier, give or take. 1199 00:53:08,232 --> 00:53:08,940 It was a low bar. 1200 00:53:08,940 --> 00:53:10,410 It was very easy to make it look prettier. 1201 00:53:10,410 --> 00:53:11,993 And we can now switch between the two. 1202 00:53:11,993 --> 00:53:14,970 However, this is not a great blog, in that we only have one post. 1203 00:53:14,970 --> 00:53:16,890 It's a hardcoded post. 1204 00:53:16,890 --> 00:53:19,770 And that's kind of derpy, not that this whole thing isn't derpy. 1205 00:53:19,770 --> 00:53:21,839 But it's a little derpier than usual. 1206 00:53:21,839 --> 00:53:23,130 So we're going to go back here. 1207 00:53:23,130 --> 00:53:27,430 And sorry if I speed up a little, but I don't want to run out of too much time. 1208 00:53:27,430 --> 00:53:29,280 And we'll go to stage 4. 1209 00:53:29,280 --> 00:53:33,757 And we'll say, OK, so we've gotten some things working a little bit better. 1210 00:53:33,757 --> 00:53:35,340 Also, I didn't explain this very well. 1211 00:53:35,340 --> 00:53:37,250 And I will stop and explain it for a second. 1212 00:53:37,250 --> 00:53:40,110 The reason I put this base.html in the root project 1213 00:53:40,110 --> 00:53:45,630 is, generally speaking, my whole web app should be pretty consistent, I think. 1214 00:53:45,630 --> 00:53:50,612 And so I want to put this base.html in the thing that governs everything. 1215 00:53:50,612 --> 00:53:53,070 I think that that makes a lot of sense if you're inheriting 1216 00:53:53,070 --> 00:53:55,350 something that is standard across. 1217 00:53:55,350 --> 00:53:58,140 No matter what kind of other applications we have running here, 1218 00:53:58,140 --> 00:53:59,430 they should all look the same. 1219 00:53:59,430 --> 00:54:01,090 It should be very user-consistent. 1220 00:54:01,090 --> 00:54:05,010 I don't want my user to be jarred by like banana slug orange. 1221 00:54:05,010 --> 00:54:06,000 Yellow? 1222 00:54:06,000 --> 00:54:08,700 And so that's why I actually rationalized 1223 00:54:08,700 --> 00:54:10,890 putting this template set here. 1224 00:54:10,890 --> 00:54:14,490 In CS50, we use layout.html instead of base.html. 1225 00:54:14,490 --> 00:54:16,530 I just think base is more intuitive for myself. 1226 00:54:16,530 --> 00:54:19,321 And I think in general, it doesn't change much about the semantics. 1227 00:54:19,321 --> 00:54:21,390 So that is what's going on there. 1228 00:54:21,390 --> 00:54:23,510 We are now in stage 4. 1229 00:54:23,510 --> 00:54:26,679 And what's going on here is very similar. 1230 00:54:26,679 --> 00:54:29,970 We're actually now changing a little bit about what's going on in the back end. 1231 00:54:29,970 --> 00:54:32,897 So we go into views.py. 1232 00:54:32,897 --> 00:54:34,230 And we haven't changed too much. 1233 00:54:34,230 --> 00:54:37,320 But I've been putting this requests library, which, for some reason, 1234 00:54:37,320 --> 00:54:39,570 I thought was included by default in Python. 1235 00:54:39,570 --> 00:54:43,990 I'd just deluded myself by having it installed on my base computer. 1236 00:54:43,990 --> 00:54:48,410 So if we go into here, we'll see posts has changed a little bit. 1237 00:54:48,410 --> 00:54:50,199 And so I use this list comprehension here. 1238 00:54:50,199 --> 00:54:52,740 If it doesn't make any sense, I'll explain it really briefly. 1239 00:54:52,740 --> 00:54:55,150 But what is worth shouting out is lorem ipsum-- 1240 00:54:55,150 --> 00:54:59,089 or loripsum-- hmm, never really read that. loripsum.net, 1241 00:54:59,089 --> 00:55:00,380 they built all their own stuff. 1242 00:55:00,380 --> 00:55:01,296 Theirs is really cool. 1243 00:55:01,296 --> 00:55:02,490 I take no credit for that. 1244 00:55:02,490 --> 00:55:07,710 I'm just using their API to get a bunch of blog posts for our random Django 1245 00:55:07,710 --> 00:55:10,060 application. 1246 00:55:10,060 --> 00:55:12,520 And then you'll notice that my context is now a list. 1247 00:55:12,520 --> 00:55:15,311 So we're going to go look at how that changed our templating engine 1248 00:55:15,311 --> 00:55:18,240 syntax, which is now a list of each of those posts. 1249 00:55:18,240 --> 00:55:19,887 I do like this element.strip. 1250 00:55:19,887 --> 00:55:21,720 That just takes off new lines and whitespace 1251 00:55:21,720 --> 00:55:23,130 on either side of the string. 1252 00:55:23,130 --> 00:55:26,310 It assumes that it's a string for element in. 1253 00:55:26,310 --> 00:55:29,550 This is the response that we got from our beautiful API. 1254 00:55:29,550 --> 00:55:31,440 The text version of that response, I happen 1255 00:55:31,440 --> 00:55:34,790 to know it delivers text, the plain text part of their API. 1256 00:55:34,790 --> 00:55:36,197 And then I split it by lines. 1257 00:55:36,197 --> 00:55:39,030 And I stripped off all the whitespace on either side of those lines. 1258 00:55:39,030 --> 00:55:41,520 And as long as there is an actual element there-- so in case 1259 00:55:41,520 --> 00:55:43,311 they had a double new line somewhere, which 1260 00:55:43,311 --> 00:55:45,600 would end up being its own element in this list, that 1261 00:55:45,600 --> 00:55:48,480 just gets ignored, because it gets counted in Python as not existing 1262 00:55:48,480 --> 00:55:50,200 or IF fails. 1263 00:55:50,200 --> 00:55:52,230 So this is just kind of a really convenient way. 1264 00:55:52,230 --> 00:55:54,920 It's pretty readable, I think, once you get used to it, 1265 00:55:54,920 --> 00:55:57,584 for just going through and doing that very quickly. 1266 00:55:57,584 --> 00:55:59,250 And then we do the same thing as before. 1267 00:55:59,250 --> 00:56:00,300 We deliver this request. 1268 00:56:00,300 --> 00:56:03,060 We have our posts.html and then our context. 1269 00:56:03,060 --> 00:56:06,422 And that all should hopefully make sense to everyone. 1270 00:56:06,422 --> 00:56:09,130 So then we're going to go look at how that changed our templates. 1271 00:56:09,130 --> 00:56:11,896 So if we go into templates, posts, most things 1272 00:56:11,896 --> 00:56:13,270 haven't really changed that much. 1273 00:56:13,270 --> 00:56:14,490 We've added JavaScript. 1274 00:56:14,490 --> 00:56:17,739 And we're not going to talk about that too much, because this is about Django. 1275 00:56:17,739 --> 00:56:19,980 But I thought it was kind of cute and quirky. 1276 00:56:19,980 --> 00:56:21,340 I'm a huge fan of randomness. 1277 00:56:21,340 --> 00:56:23,980 So then this has changed, though, for us. 1278 00:56:23,980 --> 00:56:28,830 So what's going on here is, it's roughly like writing Python, just in HTML. 1279 00:56:28,830 --> 00:56:32,100 And the reason I say roughly like that is because we're not actually 1280 00:56:32,100 --> 00:56:33,870 writing Python in HTML. 1281 00:56:33,870 --> 00:56:37,500 There's no running of some sort of Python code in the browser. 1282 00:56:37,500 --> 00:56:42,090 But on our side, on the server side, we do actually execute some code 1283 00:56:42,090 --> 00:56:43,680 and generate some HTML. 1284 00:56:43,680 --> 00:56:46,080 And this might not seem too big of a deal 1285 00:56:46,080 --> 00:56:48,466 to those of us who grew up in this generation. 1286 00:56:48,466 --> 00:56:50,340 However, as someone who used to not know what 1287 00:56:50,340 --> 00:56:53,940 this was, what templating engines were and wrote out all of his own HTML, 1288 00:56:53,940 --> 00:56:54,790 it sucked. 1289 00:56:54,790 --> 00:56:55,630 It was awful. 1290 00:56:55,630 --> 00:56:57,900 So writing this is much more eloquent. 1291 00:56:57,900 --> 00:57:00,240 I can do things very extensively. 1292 00:57:00,240 --> 00:57:02,940 And it's a much more dynamic way of writing code. 1293 00:57:02,940 --> 00:57:06,240 So we do four posts in posts. 1294 00:57:06,240 --> 00:57:09,840 Now, you'll notice posts is the new variable that I actually send in. 1295 00:57:09,840 --> 00:57:12,510 It's defined as a key in our context dictionary. 1296 00:57:12,510 --> 00:57:15,570 And when I go through posts, it's going to just take 1297 00:57:15,570 --> 00:57:19,950 each item in that list, which is the value of posts in our dictionary. 1298 00:57:19,950 --> 00:57:23,490 And it will give me access to that variable here. 1299 00:57:23,490 --> 00:57:28,500 And so I now can run and do all sorts of actual dynamic generation 1300 00:57:28,500 --> 00:57:29,492 of a bunch of posts. 1301 00:57:29,492 --> 00:57:30,950 I can change how many get rendered. 1302 00:57:30,950 --> 00:57:32,910 That's totally reasonable for us. 1303 00:57:32,910 --> 00:57:35,040 This is Rango Post #. 1304 00:57:35,040 --> 00:57:37,080 And then I do the forloop.counter. 1305 00:57:37,080 --> 00:57:39,960 I believe it's counter 0 if you want a zero-indexed counter. 1306 00:57:39,960 --> 00:57:42,810 Otherwise, for loops in Django's templating engine syntax 1307 00:57:42,810 --> 00:57:45,420 actually are one-indexed. 1308 00:57:45,420 --> 00:57:48,030 I don't know the reason for that, but I don't mind. 1309 00:57:48,030 --> 00:57:49,610 Again, more unapplied migrations. 1310 00:57:49,610 --> 00:57:50,777 We're ignoring that for now. 1311 00:57:50,777 --> 00:57:52,609 We'll get to it, I think, in the next stage. 1312 00:57:52,609 --> 00:57:54,330 But hey, we now have a bunch of posts. 1313 00:57:54,330 --> 00:57:56,970 And you know when I said that the JavaScript was kind of cute, 1314 00:57:56,970 --> 00:57:58,490 it changes the-- 1315 00:57:58,490 --> 00:58:00,330 eh, yeah, they're different colors. 1316 00:58:00,330 --> 00:58:02,220 But you'll notice we have all 10 posts. 1317 00:58:02,220 --> 00:58:02,940 And that's great. 1318 00:58:02,940 --> 00:58:03,990 That's what we would expect to see. 1319 00:58:03,990 --> 00:58:06,150 If we reload the page, they'll all be different. 1320 00:58:06,150 --> 00:58:08,130 And that's because the API just generates them randomly. 1321 00:58:08,130 --> 00:58:08,850 So that's very cool. 1322 00:58:08,850 --> 00:58:09,558 It's very random. 1323 00:58:09,558 --> 00:58:11,130 It's very Django rango. 1324 00:58:11,130 --> 00:58:12,150 And if we go to Home. 1325 00:58:12,150 --> 00:58:12,870 That should still work. 1326 00:58:12,870 --> 00:58:14,400 It hasn't really changed a whole lot. 1327 00:58:14,400 --> 00:58:15,750 I think I might have changed some words or something. 1328 00:58:15,750 --> 00:58:16,710 Who knows? 1329 00:58:16,710 --> 00:58:19,680 But the main focus being here that we now have a list of posts. 1330 00:58:19,680 --> 00:58:21,292 They're all separated out. 1331 00:58:21,292 --> 00:58:22,500 You might think this is ugly. 1332 00:58:22,500 --> 00:58:23,430 I might agree. 1333 00:58:23,430 --> 00:58:25,290 We can all just move on. 1334 00:58:25,290 --> 00:58:32,280 And so we can now go on to stage 5, which is here. 1335 00:58:32,280 --> 00:58:33,430 There we go. 1336 00:58:33,430 --> 00:58:36,369 And when we go on to stage 5, we might be saying, OK, 1337 00:58:36,369 --> 00:58:37,410 what else is there to do. 1338 00:58:37,410 --> 00:58:39,210 You've really taken this contrived concept. 1339 00:58:39,210 --> 00:58:40,501 You've beat it into the ground. 1340 00:58:40,501 --> 00:58:42,515 You've drilled it into our heads. 1341 00:58:42,515 --> 00:58:44,390 And we're going to do that a little bit more. 1342 00:58:44,390 --> 00:58:48,850 So now, when we go into web, same directory structure. 1343 00:58:48,850 --> 00:58:51,040 You should be like, yes, we are familiar with this. 1344 00:58:51,040 --> 00:58:52,160 Don't say it again. 1345 00:58:52,160 --> 00:58:53,860 And I'll be like, yes, you're right. 1346 00:58:53,860 --> 00:58:58,087 We've added another one so that we can actually modify what's going on here. 1347 00:58:58,087 --> 00:58:59,670 Now, this looks quite a bit different. 1348 00:58:59,670 --> 00:59:01,930 But you'll notice it's actually not too bad. 1349 00:59:01,930 --> 00:59:03,260 It's the same thing here. 1350 00:59:03,260 --> 00:59:04,640 This is what we've seen before. 1351 00:59:04,640 --> 00:59:06,181 But I've added another version of it. 1352 00:59:06,181 --> 00:59:07,150 There's also this one. 1353 00:59:07,150 --> 00:59:10,150 It uses another API, very well written, not mine. 1354 00:59:10,150 --> 00:59:12,550 I did not build any of that API. 1355 00:59:12,550 --> 00:59:15,040 That was built by Samir Kumar. 1356 00:59:15,040 --> 00:59:17,650 And that's all I have on that one. 1357 00:59:17,650 --> 00:59:18,970 But it's a really good thing. 1358 00:59:18,970 --> 00:59:20,886 And it has a bunch of geeky jokes that I think 1359 00:59:20,886 --> 00:59:22,750 are really funny, because, you know, geeky. 1360 00:59:22,750 --> 00:59:26,854 And so that one just takes the first 10. 1361 00:59:26,854 --> 00:59:29,020 This underscore just means don't actually assign it. 1362 00:59:29,020 --> 00:59:30,220 Don't do a variable for it. 1363 00:59:30,220 --> 00:59:31,630 Just count through 10. 1364 00:59:31,630 --> 00:59:36,140 Range is what you use in Python to iterate through a range of numbers. 1365 00:59:36,140 --> 00:59:40,650 And so then this says, if post_type equals equals geeky, which is a string. 1366 00:59:40,650 --> 00:59:42,550 And you're like, where is post_type? 1367 00:59:42,550 --> 00:59:44,091 Where do you keep getting these from? 1368 00:59:44,091 --> 00:59:45,681 And I'm like, yeah, you're right. 1369 00:59:45,681 --> 00:59:47,680 And so you'll notice, I actually defined context 1370 00:59:47,680 --> 00:59:51,460 up here so that I can append to it down here if I need to. 1371 00:59:51,460 --> 00:59:53,600 And then I have post_type. 1372 00:59:53,600 --> 00:59:56,990 And you're like, wait, didn't you say that this only takes in a request, 1373 00:59:56,990 --> 00:59:58,676 returns HTTP response? 1374 00:59:58,676 --> 00:59:59,800 And I will say, yes, I did. 1375 00:59:59,800 --> 01:00:01,966 I'm retracting that, kind of like your chem teachers 1376 01:00:01,966 --> 01:00:03,970 did once you got to college. 1377 01:00:03,970 --> 01:00:05,410 Things have been changed here. 1378 01:00:05,410 --> 01:00:06,940 And I'm going to explain why. 1379 01:00:06,940 --> 01:00:09,940 So if you'll recall, I said that URLs in Django 1380 01:00:09,940 --> 01:00:12,760 can actually be used to do all sorts of really cool things. 1381 01:00:12,760 --> 01:00:15,280 In fact, you can use them to pass parameters 1382 01:00:15,280 --> 01:00:17,780 to the function that deals with it, the view. 1383 01:00:17,780 --> 01:00:20,440 And so that's what we've done here is I defined some string. 1384 01:00:20,440 --> 01:00:23,110 And I matched it with post_type equals equals geeky. 1385 01:00:23,110 --> 01:00:25,630 And then I do something different based on that. 1386 01:00:25,630 --> 01:00:28,980 Otherwise, just go back to our default, which is lorem ipsum. 1387 01:00:28,980 --> 01:00:32,987 And so you look in urls.py, things have been modified a little bit. 1388 01:00:32,987 --> 01:00:34,570 So we've done a couple of things here. 1389 01:00:34,570 --> 01:00:38,980 But we're going to focus on this first path thing, which is posts/. 1390 01:00:38,980 --> 01:00:42,054 And this takes in these like less than, greater than signs. 1391 01:00:42,054 --> 01:00:43,720 I don't know the general term for these. 1392 01:00:43,720 --> 01:00:46,330 And it causes me a lot of angst when I'm trying 1393 01:00:46,330 --> 01:00:50,080 to explain stuff to people, because I'm like, this, this thing. 1394 01:00:50,080 --> 01:00:52,657 And I use less than, greater than. 1395 01:00:52,657 --> 01:00:54,490 If someone knows that, someone will tell me, 1396 01:00:54,490 --> 01:00:56,560 I'm sure, in the left while doing so. 1397 01:00:56,560 --> 01:00:59,430 So what this says is, if you go to posts/, 1398 01:00:59,430 --> 01:01:03,640 and whatever you put here is going to be called post_type and sent as a variable 1399 01:01:03,640 --> 01:01:06,077 or passed as a parameter to our view posts. 1400 01:01:06,077 --> 01:01:09,160 And that's what we've done is we've said, hey, whatever gets passed there, 1401 01:01:09,160 --> 01:01:11,440 match that with either geeky or anything. 1402 01:01:11,440 --> 01:01:13,534 And then do different things accordingly. 1403 01:01:13,534 --> 01:01:14,950 And that's really important to us. 1404 01:01:14,950 --> 01:01:16,840 Now, you'll also notice, hey, where'd this come from. 1405 01:01:16,840 --> 01:01:18,890 This is random and doesn't make any sense. 1406 01:01:18,890 --> 01:01:21,040 I added a different view, because I am sneaky. 1407 01:01:21,040 --> 01:01:24,347 And I said, hey, actually anytime you add a favorite, pass in the quote 1408 01:01:24,347 --> 01:01:25,180 that you want to do. 1409 01:01:25,180 --> 01:01:26,800 And you're like, what is this. 1410 01:01:26,800 --> 01:01:27,880 This is so random. 1411 01:01:27,880 --> 01:01:31,300 And I will say, random, Django, rango. 1412 01:01:31,300 --> 01:01:33,220 And so yes, what actually is going on here 1413 01:01:33,220 --> 01:01:35,800 is we are also adding in the functionality of being 1414 01:01:35,800 --> 01:01:37,992 able to select certain posts as our favorites 1415 01:01:37,992 --> 01:01:39,700 and have them get stored to the database. 1416 01:01:39,700 --> 01:01:41,110 And you're like, database? 1417 01:01:41,110 --> 01:01:42,760 And I'm like, database. 1418 01:01:42,760 --> 01:01:44,720 And we're going to build a model. 1419 01:01:44,720 --> 01:01:48,280 And so when we get to models.py, this is what's going on. 1420 01:01:48,280 --> 01:01:51,790 I built a class, because, hey, models are just Python classes. 1421 01:01:51,790 --> 01:01:54,150 favorite(models.Model). 1422 01:01:54,150 --> 01:01:57,040 Yeah, models gets imported by default. So that's cool. 1423 01:01:57,040 --> 01:02:00,011 And this just extends the model base class from Django. 1424 01:02:00,011 --> 01:02:03,010 And then we say body, which is actually going to be a field in the model 1425 01:02:03,010 --> 01:02:07,000 or an aspect of our class or, if you're really thinking ahead, you're like, 1426 01:02:07,000 --> 01:02:11,590 wait a second, that's a column in our table called favorite. 1427 01:02:11,590 --> 01:02:12,610 And you're right. 1428 01:02:12,610 --> 01:02:17,380 And so they follow the same general practices as Python classes do. 1429 01:02:17,380 --> 01:02:18,850 You generally will capitalize them. 1430 01:02:18,850 --> 01:02:22,990 They will be not camel case but just uppercase every word, no spaces, 1431 01:02:22,990 --> 01:02:23,980 certainly no spaces. 1432 01:02:23,980 --> 01:02:24,970 That's absurd. 1433 01:02:24,970 --> 01:02:27,130 But no underscores either. 1434 01:02:27,130 --> 01:02:28,750 Generally, you'll see this. 1435 01:02:28,750 --> 01:02:31,510 I only have one field here, because again, contrived 1436 01:02:31,510 --> 01:02:33,370 random Django example, rango. 1437 01:02:33,370 --> 01:02:35,110 And we do models.TextField. 1438 01:02:35,110 --> 01:02:39,311 There's a great reference on Django's documentation 1439 01:02:39,311 --> 01:02:41,310 that explains all of these different fields, all 1440 01:02:41,310 --> 01:02:42,560 of their different parameters. 1441 01:02:42,560 --> 01:02:43,600 And they take a million. 1442 01:02:43,600 --> 01:02:46,300 And then I also define this underscore underscore string. 1443 01:02:46,300 --> 01:02:48,910 It's a cool attribute to define for classes. 1444 01:02:48,910 --> 01:02:51,640 It overrides the default and says, actually, just 1445 01:02:51,640 --> 01:02:55,690 return favorite quotes number of this item's ID. 1446 01:02:55,690 --> 01:03:01,450 That way, it doesn't do the weird this of objects, favorite object, 1447 01:03:01,450 --> 01:03:02,632 or whatever it is. 1448 01:03:02,632 --> 01:03:05,090 So that's actually a really convenient way of doing things. 1449 01:03:05,090 --> 01:03:09,250 And I would definitely recommend it as a generalist practice. 1450 01:03:09,250 --> 01:03:10,600 So cool. 1451 01:03:10,600 --> 01:03:12,790 That also, I realize, might not make any sense, 1452 01:03:12,790 --> 01:03:15,414 because it's on the admin interface, which I didn't talk about. 1453 01:03:15,414 --> 01:03:18,600 And so if you were really curious about where this comes into play, 1454 01:03:18,600 --> 01:03:20,308 go ahead and explore the admin interface. 1455 01:03:20,308 --> 01:03:22,390 And that's really cool. 1456 01:03:22,390 --> 01:03:23,620 So we've created a model. 1457 01:03:23,620 --> 01:03:27,966 And then you're like, wait, but you also called this addfavorite thing in views. 1458 01:03:27,966 --> 01:03:29,590 And I deliberately didn't show us that. 1459 01:03:29,590 --> 01:03:30,050 And you're right. 1460 01:03:30,050 --> 01:03:30,700 It's here. 1461 01:03:30,700 --> 01:03:33,790 In fact, we do this really bad exception practicing where we say, 1462 01:03:33,790 --> 01:03:38,770 hey, any exception that ever occurs, just return false, yay. 1463 01:03:38,770 --> 01:03:40,735 And so we're returning JSON responses now. 1464 01:03:40,735 --> 01:03:42,250 And you're like, well, that's new. 1465 01:03:42,250 --> 01:03:44,090 And I'm like, yeah, you're right. 1466 01:03:44,090 --> 01:03:46,110 And so what basically is happening here-- 1467 01:03:46,110 --> 01:03:48,750 I'll try and get that all on this screen-- 1468 01:03:48,750 --> 01:03:51,800 is, if for our method is get, if the request that's given to us 1469 01:03:51,800 --> 01:03:53,780 is actually a get request, then we're going 1470 01:03:53,780 --> 01:03:57,590 to create a new favorite object, set its body equivalent to whatever 1471 01:03:57,590 --> 01:04:00,800 the quote was, and remember, that's the pattern or the thing 1472 01:04:00,800 --> 01:04:02,060 that we passed in here. 1473 01:04:02,060 --> 01:04:05,810 That's the variable from our actual URL, Django URLs. 1474 01:04:05,810 --> 01:04:08,960 And then we're going to save it to our database 1475 01:04:08,960 --> 01:04:13,730 and then return back to whoever sent this request as a response, a JSON 1476 01:04:13,730 --> 01:04:17,270 response, which is imported up here, and have 1477 01:04:17,270 --> 01:04:22,040 that be just the dictionary mapping the key data to the value true, 1478 01:04:22,040 --> 01:04:23,180 because all of it worked. 1479 01:04:23,180 --> 01:04:24,306 Everything was good. 1480 01:04:24,306 --> 01:04:26,930 Otherwise, anytime an error occurred or things were unexpected, 1481 01:04:26,930 --> 01:04:28,200 just return false. 1482 01:04:28,200 --> 01:04:30,560 Now, I think you can hopefully see how this could maybe 1483 01:04:30,560 --> 01:04:32,450 be built a little bit more eloquently. 1484 01:04:32,450 --> 01:04:34,200 And I will agree with you there. 1485 01:04:34,200 --> 01:04:35,340 I pointed it out. 1486 01:04:35,340 --> 01:04:38,900 And so we'll talk about that in a second maybe. 1487 01:04:38,900 --> 01:04:42,110 But if we go into posts.html, you'll notice 1488 01:04:42,110 --> 01:04:45,530 we included a second JavaScript, favorites.js. 1489 01:04:45,530 --> 01:04:52,220 We're writing all of those into our rango, static, web, js, boom. 1490 01:04:52,220 --> 01:04:56,339 And once we get there, we might say something like, OK, cool. 1491 01:04:56,339 --> 01:04:57,380 It does a bunch of stuff. 1492 01:04:57,380 --> 01:04:59,170 It does some Ajax requesting. 1493 01:04:59,170 --> 01:05:00,710 And we'll briefly cover that. 1494 01:05:00,710 --> 01:05:01,522 It looks like this. 1495 01:05:01,522 --> 01:05:04,730 We're not really going to discuss what exactly is going on here, because it's 1496 01:05:04,730 --> 01:05:06,650 not relevant to Django explicitly. 1497 01:05:06,650 --> 01:05:09,020 But it is worth going through and understanding. 1498 01:05:09,020 --> 01:05:12,800 And it uses our add_favorite url, which is really the point of this. 1499 01:05:12,800 --> 01:05:14,717 And then it appends text to it. 1500 01:05:14,717 --> 01:05:16,550 That's the quote that we wanted to favorite. 1501 01:05:16,550 --> 01:05:21,020 So now, if we do this whole run server shebang, 1502 01:05:21,020 --> 01:05:25,160 this one will actually tell us that we have no unapplied migrations. 1503 01:05:25,160 --> 01:05:27,200 I don't think that's true. 1504 01:05:27,200 --> 01:05:31,430 So we're going to talk about what it means to apply a migration, 1505 01:05:31,430 --> 01:05:33,072 to make a migration, to migrate. 1506 01:05:33,072 --> 01:05:34,280 We don't mean like the birds. 1507 01:05:34,280 --> 01:05:36,880 We mean like Django. 1508 01:05:36,880 --> 01:05:39,594 Got to love all the weird animal references in coding for Python, 1509 01:05:39,594 --> 01:05:42,260 because it's like a snake, but it's also a programming language. 1510 01:05:42,260 --> 01:05:43,250 I think that's funny. 1511 01:05:43,250 --> 01:05:44,140 Ignore my jokes. 1512 01:05:44,140 --> 01:05:48,530 Manage.py, management interface, we're going to make migrations. 1513 01:05:48,530 --> 01:05:50,040 And no changes were detected. 1514 01:05:50,040 --> 01:05:52,790 So I must have done this by accident when I was tired. 1515 01:05:52,790 --> 01:05:53,597 But that's OK. 1516 01:05:53,597 --> 01:05:55,430 That is going to be the first step that says 1517 01:05:55,430 --> 01:05:59,240 take all of the database changes of the changes to models.py, and update them. 1518 01:05:59,240 --> 01:06:00,890 And then we're going to migrate across. 1519 01:06:00,890 --> 01:06:04,820 And so you'll notice it applies across admin, off content type, sessions. 1520 01:06:04,820 --> 01:06:06,020 Those are all built-ins. 1521 01:06:06,020 --> 01:06:08,150 And web, which is good, because we included that. 1522 01:06:08,150 --> 01:06:11,210 You can also migrate particular apps by passing them in as a parameter. 1523 01:06:11,210 --> 01:06:13,682 Just apply web migrations. 1524 01:06:13,682 --> 01:06:15,140 Things like that are really useful. 1525 01:06:15,140 --> 01:06:18,720 You can also roll back migrations, roll forward migrations, things like that. 1526 01:06:18,720 --> 01:06:22,160 And so we might then say, OK, cool, cool. 1527 01:06:22,160 --> 01:06:24,140 I was doing a reverse search, by the way. 1528 01:06:24,140 --> 01:06:26,470 And that was entirely useless. 1529 01:06:26,470 --> 01:06:27,830 We can just go up, boom. 1530 01:06:27,830 --> 01:06:30,300 Running the server, nothing else to check. 1531 01:06:30,300 --> 01:06:31,550 We just get a bunch of output. 1532 01:06:31,550 --> 01:06:34,550 And we're going to go, OK, this will hopefully do something. 1533 01:06:34,550 --> 01:06:35,700 Cool, we got Rango. 1534 01:06:35,700 --> 01:06:38,514 And so you'll notice, actually, in our nav bar-- 1535 01:06:38,514 --> 01:06:39,430 it looks really small. 1536 01:06:39,430 --> 01:06:41,020 I'm sorry if I'm straining your eyes. 1537 01:06:41,020 --> 01:06:43,220 We have both lorem ipsum and geeky quotes. 1538 01:06:43,220 --> 01:06:46,400 Lorem ipsum has not changed. 1539 01:06:46,400 --> 01:06:48,059 This is ugly, and it's off to the side. 1540 01:06:48,059 --> 01:06:49,850 I don't think I corrected it in this stage. 1541 01:06:49,850 --> 01:06:51,680 It's corrected in the next stage. 1542 01:06:51,680 --> 01:06:53,330 I generally prefer to center stuff. 1543 01:06:53,330 --> 01:06:54,840 And we have quote one. 1544 01:06:54,840 --> 01:06:55,790 I can click favorite. 1545 01:06:55,790 --> 01:06:58,380 And it'll say, hey, quote one was favorited successfully. 1546 01:06:58,380 --> 01:06:59,732 And I'm like, woo! 1547 01:06:59,732 --> 01:07:01,190 And then we can go to geeky quotes. 1548 01:07:01,190 --> 01:07:06,260 And we can say, oh, Chuck Norris can touch MC Hammer, funny. 1549 01:07:06,260 --> 01:07:09,980 And so these are just kind of a funny set of jokes that are kind of cute. 1550 01:07:09,980 --> 01:07:12,170 Again, pulled from an API that I did not write. 1551 01:07:12,170 --> 01:07:15,050 And we might say, if by some incredible spacetime paradox, 1552 01:07:15,050 --> 01:07:17,390 Chuck Norris would ever fight himself, he'd win, period. 1553 01:07:17,390 --> 01:07:20,112 That's hilarious. 1554 01:07:20,112 --> 01:07:23,320 We can then favorite it and say, cool, we thought that was hilarious as heck. 1555 01:07:23,320 --> 01:07:25,710 We get an alert that says it was favorited successfully. 1556 01:07:25,710 --> 01:07:27,260 So we might say, cool. 1557 01:07:27,260 --> 01:07:30,620 You'll get all this output here, because we're copying quotes into a URL. 1558 01:07:30,620 --> 01:07:32,120 There are better ways of doing that. 1559 01:07:32,120 --> 01:07:35,030 But we're not going to really discuss them here. 1560 01:07:35,030 --> 01:07:36,480 Oh, I'm a dummy. 1561 01:07:36,480 --> 01:07:41,090 Control-C, Control-L to stop and then clear up content. 1562 01:07:41,090 --> 01:07:44,240 And then we're going to go into stage 6 very briefly, 1563 01:07:44,240 --> 01:07:46,380 because I am roughly out of time. 1564 01:07:46,380 --> 01:07:51,830 So in stage 6, we have done a little bit of what is roughly the right wrap-up. 1565 01:07:51,830 --> 01:07:53,810 We haven't implemented all of the features that 1566 01:07:53,810 --> 01:07:55,020 are on the latest version. 1567 01:07:55,020 --> 01:07:56,480 You can look at those in stage 7. 1568 01:07:56,480 --> 01:07:58,300 But we have implemented quite a bit. 1569 01:07:58,300 --> 01:08:02,030 So in stage 6, we've said, you know what, we should also 1570 01:08:02,030 --> 01:08:03,540 be able to look at the favorites. 1571 01:08:03,540 --> 01:08:05,330 We're just saving them to the database. 1572 01:08:05,330 --> 01:08:06,380 What the heck, man? 1573 01:08:06,380 --> 01:08:09,635 I want to actually understand what our favorites were. 1574 01:08:09,635 --> 01:08:10,760 What did other people like? 1575 01:08:10,760 --> 01:08:11,426 What did I like? 1576 01:08:11,426 --> 01:08:12,420 Things like that. 1577 01:08:12,420 --> 01:08:15,930 And so we'll see, hey, we rendered some favorites.html. 1578 01:08:15,930 --> 01:08:18,170 And you're like, oh, that makes sense. 1579 01:08:18,170 --> 01:08:20,420 And so again, we're just extending from base. 1580 01:08:20,420 --> 01:08:22,160 This should all be fairly familiar. 1581 01:08:22,160 --> 01:08:23,870 We just changed the title to favorites. 1582 01:08:23,870 --> 01:08:27,859 And then we say, all right, iterate through every favorite. 1583 01:08:27,859 --> 01:08:29,779 Call it favorite number whatever. 1584 01:08:29,779 --> 01:08:33,000 We're giving them some ID now so I can use JavaScript to deal with them. 1585 01:08:33,000 --> 01:08:34,399 And we do favorite.body. 1586 01:08:34,399 --> 01:08:36,179 OK, so that's a little new. 1587 01:08:36,179 --> 01:08:39,470 And you're like, hmm, I don't know where that might have intuitively come from. 1588 01:08:39,470 --> 01:08:41,890 And everything else has just not changed. 1589 01:08:41,890 --> 01:08:44,850 And so I would then say, OK, cool. 1590 01:08:44,850 --> 01:08:47,140 Let's look at posts, make sure nothing here changed. 1591 01:08:47,140 --> 01:08:48,279 Yeah, seems about right. 1592 01:08:48,279 --> 01:08:53,200 So then when we go into views.py, index is still the same. 1593 01:08:53,200 --> 01:08:56,556 We import all the same stuff, except we also import our models here. 1594 01:08:56,556 --> 01:08:59,430 We did that before as well, but it's just kind of worth pointing out. 1595 01:08:59,430 --> 01:09:00,479 And we go through. 1596 01:09:00,479 --> 01:09:01,529 Posts looks right. 1597 01:09:01,529 --> 01:09:02,250 That's good. 1598 01:09:02,250 --> 01:09:04,200 Favorites, OK, that's cool. 1599 01:09:04,200 --> 01:09:06,210 Favorite objects all, huh. 1600 01:09:06,210 --> 01:09:08,819 So this is how you actually interface with retrieving things 1601 01:09:08,819 --> 01:09:10,082 from the database in Django. 1602 01:09:10,082 --> 01:09:12,540 I always love feigning surprise when I look at my own code. 1603 01:09:12,540 --> 01:09:14,460 I'm like, wow, that's new. 1604 01:09:14,460 --> 01:09:18,060 So basically, what we're doing here is whenever we get to favorites, the view, 1605 01:09:18,060 --> 01:09:20,294 then we're going to say, hey, here's our context, 1606 01:09:20,294 --> 01:09:23,460 favorites-- that makes sense, because we remember what we wrote in our HTML. 1607 01:09:23,460 --> 01:09:24,990 And then we do favorite.objects.all. 1608 01:09:24,990 --> 01:09:29,040 And we take just all of the objects that are in the favorites table, so 1609 01:09:29,040 --> 01:09:30,149 basically just every row. 1610 01:09:30,149 --> 01:09:35,189 You can think of this as like select* from favorite. 1611 01:09:35,189 --> 01:09:36,750 And it just pulls them all up. 1612 01:09:36,750 --> 01:09:38,939 It gives you a query set. 1613 01:09:38,939 --> 01:09:40,479 So it's distinct from a list. 1614 01:09:40,479 --> 01:09:42,990 But it's roughly just an iterable object that 1615 01:09:42,990 --> 01:09:45,750 contains each of those rows as their own independent objects. 1616 01:09:45,750 --> 01:09:48,990 And because each object is its own favorite object, 1617 01:09:48,990 --> 01:09:53,090 that's where we actually understood that we could use, in favorites.html, 1618 01:09:53,090 --> 01:09:57,270 favorite.body, because we know that as long as we have an actual favorite 1619 01:09:57,270 --> 01:09:59,040 object-- 1620 01:09:59,040 --> 01:10:00,810 that's a little bit weird in English-- 1621 01:10:00,810 --> 01:10:02,945 we can actually access its attributes here. 1622 01:10:02,945 --> 01:10:05,070 So that's what we're going to be allowed to render. 1623 01:10:05,070 --> 01:10:07,050 Now, we've added some favorites. 1624 01:10:07,050 --> 01:10:10,740 And you might be like, OK, but I'm not getting it to work, Nicholas. 1625 01:10:10,740 --> 01:10:11,940 And I would agree. 1626 01:10:11,940 --> 01:10:14,740 urls.py is still really important to us. 1627 01:10:14,740 --> 01:10:16,890 We're going to want to make sure that in path, we 1628 01:10:16,890 --> 01:10:21,930 added a way to get any request that goes to favorites to get to the view 1629 01:10:21,930 --> 01:10:24,100 favorites and deal something accordingly. 1630 01:10:24,100 --> 01:10:27,242 So in order to prove my point, we're going to run server. 1631 01:10:27,242 --> 01:10:30,450 And we're going to double check there are no unapplied migrations, because we 1632 01:10:30,450 --> 01:10:32,408 are actually interfacing with our database now. 1633 01:10:32,408 --> 01:10:33,900 So we do need those to work. 1634 01:10:33,900 --> 01:10:37,320 And we're going to say, all right, things should be different. 1635 01:10:37,320 --> 01:10:40,020 And this is just going to render a bunch of quotes to us again. 1636 01:10:40,020 --> 01:10:43,720 OK, apparently, I didn't fix this until way later. 1637 01:10:43,720 --> 01:10:45,840 And so now, you'll notice up in our nav bar, 1638 01:10:45,840 --> 01:10:48,630 we still have home, boom, rango, boom. 1639 01:10:48,630 --> 01:10:51,210 Lorem ipsum and geeky quotes still exist, unsurprising. 1640 01:10:51,210 --> 01:10:53,130 But favorites is now here. 1641 01:10:53,130 --> 01:10:56,160 And if we click here, we should have some favorites saved. 1642 01:10:56,160 --> 01:10:57,230 Oh, my god. 1643 01:10:57,230 --> 01:10:59,890 There are a million tests, because I was testing things. 1644 01:10:59,890 --> 01:11:01,750 And I guess that got saved to this. 1645 01:11:01,750 --> 01:11:06,090 And I think it's kind of cute that they just kind of change colors randomly, 1646 01:11:06,090 --> 01:11:07,740 because I'm a derp. 1647 01:11:07,740 --> 01:11:11,070 But you'll also notice that the things that we favorited, 1648 01:11:11,070 --> 01:11:12,750 minus this first one. 1649 01:11:12,750 --> 01:11:13,890 That was a test. 1650 01:11:13,890 --> 01:11:17,190 But these last three things that we favorited in this demo 1651 01:11:17,190 --> 01:11:19,270 are all here, which is really cool. 1652 01:11:19,270 --> 01:11:22,710 So they are listed as the favorites IDs. 1653 01:11:22,710 --> 01:11:26,464 So this is actually the literally 32nd thing that was favorited. 1654 01:11:26,464 --> 01:11:28,380 And then if you look in stage 7, I'm not going 1655 01:11:28,380 --> 01:11:29,796 to walk us all the way through it. 1656 01:11:29,796 --> 01:11:31,320 But I will run it. 1657 01:11:31,320 --> 01:11:35,520 Actually, it is running on rangodjango.herokuapp.com. 1658 01:11:35,520 --> 01:11:37,650 Stage 7 implements some other features. 1659 01:11:37,650 --> 01:11:40,350 And I guess this will be a good place to leave off. 1660 01:11:40,350 --> 01:11:44,250 It stylizes things a little bit more so we don't have quite as much whitespace. 1661 01:11:44,250 --> 01:11:46,890 I believe it puts that favorite icon in the middle. 1662 01:11:46,890 --> 01:11:50,190 It also wraps things in a border. 1663 01:11:50,190 --> 01:11:53,440 There's some contrived and derpy stylistic changes that were made. 1664 01:11:53,440 --> 01:11:55,440 But if I go and favorite this thing, it still 1665 01:11:55,440 --> 01:11:57,273 tells me that it was favorited successfully. 1666 01:11:57,273 --> 01:12:00,420 If i into favorites, I've actually arranged them 1667 01:12:00,420 --> 01:12:02,880 by the number of likes they've gotten. 1668 01:12:02,880 --> 01:12:05,820 And then you also have a like button on favorites where I can-- 1669 01:12:05,820 --> 01:12:07,020 this one is at 3. 1670 01:12:07,020 --> 01:12:07,710 This one's at 3. 1671 01:12:07,710 --> 01:12:08,610 This one's also at 3. 1672 01:12:08,610 --> 01:12:10,318 But if I click Like, then that one should 1673 01:12:10,318 --> 01:12:14,649 go to the top, which is what we'll see as soon as it reloads. 1674 01:12:14,649 --> 01:12:17,190 There are a million other ways to do this, all in JavaScript, 1675 01:12:17,190 --> 01:12:18,064 things like that. 1676 01:12:18,064 --> 01:12:19,980 But hopefully, you've gotten a little bit more 1677 01:12:19,980 --> 01:12:24,310 familiar with what exactly is going on here. 1678 01:12:24,310 --> 01:12:27,660 Yeah, that concludes our whirlwind tour of very basic web development, very 1679 01:12:27,660 --> 01:12:30,540 basic Django, and very basic Python. 1680 01:12:30,540 --> 01:12:34,740 Hopefully, you understand why I love using Python, why I love using Django, 1681 01:12:34,740 --> 01:12:37,110 and why I think it makes web development very easy. 1682 01:12:37,110 --> 01:12:40,650 Despite the fact that this is not Facebook, for example, 1683 01:12:40,650 --> 01:12:42,960 and certainly not a super aesthetic app, it 1684 01:12:42,960 --> 01:12:46,840 is definitely very cleanly written and relatively easy to understand. 1685 01:12:46,840 --> 01:12:50,580 It also does something that is not entirely contrived, although you 1686 01:12:50,580 --> 01:12:52,240 might look at that and go, yes, it is. 1687 01:12:52,240 --> 01:12:54,073 And I would say, yes, you're probably right. 1688 01:12:54,073 --> 01:12:56,520 But it is something that you can certainly build off of. 1689 01:12:56,520 --> 01:12:58,830 I encourage you to explore Django a lot more. 1690 01:12:58,830 --> 01:13:01,226 The documentation that exist for Django is fantastic. 1691 01:13:01,226 --> 01:13:03,600 And I don't think that I could ask for anything better as 1692 01:13:03,600 --> 01:13:05,550 far as good documentation goes. 1693 01:13:05,550 --> 01:13:07,934 Python similarly has fantastic documentation. 1694 01:13:07,934 --> 01:13:10,350 There are a million and one things you can do with Django. 1695 01:13:10,350 --> 01:13:13,922 And I would recommend exploring as many of them as possible. 1696 01:13:13,922 --> 01:13:15,630 This is also super mobile-friendly thanks 1697 01:13:15,630 --> 01:13:17,400 to Bootstrap, so responsive design. 1698 01:13:17,400 --> 01:13:20,760 Bootstrap is another thing, great documentation, very nice for beginners, 1699 01:13:20,760 --> 01:13:24,410 and super easy to use and customize. 1700 01:13:24,410 --> 01:13:27,210 And so all of these things, hopefully, have demonstrated to you 1701 01:13:27,210 --> 01:13:29,310 or motivated to you why Django is something that 1702 01:13:29,310 --> 01:13:31,020 is worth exploring and figuring out. 1703 01:13:31,020 --> 01:13:33,180 It is a fantastic Python development framework. 1704 01:13:33,180 --> 01:13:36,240 This is all deployed on Heroku, which is another great service. 1705 01:13:36,240 --> 01:13:37,830 I particularly love using it. 1706 01:13:37,830 --> 01:13:42,382 I swear I'm not paid by any of these organizations. 1707 01:13:42,382 --> 01:13:44,590 And I just am kind of walking advertisement for them, 1708 01:13:44,590 --> 01:13:47,860 because they've help me a lot in my own personal CS career. 1709 01:13:47,860 --> 01:13:50,560 And then Waitress is another thing that just is used underneath 1710 01:13:50,560 --> 01:13:52,240 to build all of this. 1711 01:13:52,240 --> 01:13:55,960 All of it is documented in the GitHub repository, which I 1712 01:13:55,960 --> 01:13:59,190 guess I'll bring back up through here. 1713 01:13:59,190 --> 01:14:01,690 And so yes, you are welcome to go and explore and see what's 1714 01:14:01,690 --> 01:14:05,590 going on in this Django whirlwind tour. 1715 01:14:05,590 --> 01:14:08,500 I did call it Django rango. 1716 01:14:08,500 --> 01:14:09,220 My apologies. 1717 01:14:09,220 --> 01:14:11,530 You had to hear that pun, I think, 44 times-- 1718 01:14:11,530 --> 01:14:12,760 42 times, sorry. 1719 01:14:12,760 --> 01:14:14,677 And so there's all of that. 1720 01:14:14,677 --> 01:14:15,760 Hopefully, you've enjoyed. 1721 01:14:15,760 --> 01:14:18,700 I really appreciate you watching this lecture here, now, in the past, 1722 01:14:18,700 --> 01:14:21,162 and in the future. 1723 01:14:21,162 --> 01:14:23,620 And if you have any questions, then feel free to leave them 1724 01:14:23,620 --> 01:14:25,210 in the comments in the YouTube video. 1725 01:14:25,210 --> 01:14:27,820 I am absolutely awful at answering them. 1726 01:14:27,820 --> 01:14:31,210 There are millions of people on the internet who 1727 01:14:31,210 --> 01:14:33,370 would love to answer your questions. 1728 01:14:33,370 --> 01:14:35,950 And Stack Overflow, Google, all sorts of great resources, 1729 01:14:35,950 --> 01:14:38,655 as well as the documentation for each of these things. 1730 01:14:38,655 --> 01:14:43,180 So yes, this has been Nick Wong's CS50 seminar for Django. 1731 01:14:43,180 --> 01:14:45,926 And I'm going to leave us on this cool matrixy background, 1732 01:14:45,926 --> 01:14:47,050 because I think it's nifty. 1733 01:14:47,050 --> 01:14:47,950 Thank you very much. 1734 01:14:47,950 --> 01:14:50,100 I appreciate it.