1 00:00:00,000 --> 00:00:02,964 [MUSIC PLAYING] 2 00:00:02,964 --> 00:00:15,852 3 00:00:15,852 --> 00:00:18,060 SPEAKER 1: Welcome back, everyone, to Web Programming 4 00:00:18,060 --> 00:00:19,192 with Python and JavaScript. 5 00:00:19,192 --> 00:00:21,150 So we've been spending the last couple of weeks 6 00:00:21,150 --> 00:00:23,340 working particularly on JavaScript, working 7 00:00:23,340 --> 00:00:26,700 on using JavaScript to be able to write code that runs on the client, 8 00:00:26,700 --> 00:00:29,940 runs inside the web browser, and allows us to have dynamic web 9 00:00:29,940 --> 00:00:33,849 applications that allow for animation, for instance, or for sending messages 10 00:00:33,849 --> 00:00:37,140 back and forth in real time without the user needing to reload the web browser. 11 00:00:37,140 --> 00:00:40,599 And so what we're going to do today is transition a little bit back to Python. 12 00:00:40,599 --> 00:00:43,140 So in order to build these more complicated web applications, 13 00:00:43,140 --> 00:00:45,780 we've been using a Python web framework known 14 00:00:45,780 --> 00:00:48,900 as Flask, which let us using relatively few lines of code 15 00:00:48,900 --> 00:00:51,110 pretty quickly set up a web application. 16 00:00:51,110 --> 00:00:54,630 We were able to control routes where users are requesting information 17 00:00:54,630 --> 00:00:55,846 at a particular URL. 18 00:00:55,846 --> 00:00:57,720 And we could direct them one place or another 19 00:00:57,720 --> 00:01:00,810 to show one page or another with whatever information we wanted. 20 00:01:00,810 --> 00:01:03,780 And we were able to hook Flask up to a back end database 21 00:01:03,780 --> 00:01:08,010 using PostgreSQL in order to make sure that our web application could 22 00:01:08,010 --> 00:01:11,250 manipulate data in order to add rows to tables, remove rows from tables, 23 00:01:11,250 --> 00:01:13,530 edit them, and so on and so forth. 24 00:01:13,530 --> 00:01:15,780 But a Flask is what we would call a micro framework. 25 00:01:15,780 --> 00:01:18,488 It's a pretty lightweight framework that doesn't have a whole lot 26 00:01:18,488 --> 00:01:20,410 to it, just enough to get us up and running. 27 00:01:20,410 --> 00:01:24,180 And so as people begin to work on more complicated web applications, 28 00:01:24,180 --> 00:01:28,970 there are a lot of things that start to become repetitive, that Flask will just 29 00:01:28,970 --> 00:01:32,345 start to get frustrating to have to deal with the complexities of trying 30 00:01:32,345 --> 00:01:33,720 to build things out for yourself. 31 00:01:33,720 --> 00:01:35,790 For instance, in many web applications you'll 32 00:01:35,790 --> 00:01:40,500 find that you need to add users and have systems for users to log in and be 33 00:01:40,500 --> 00:01:42,000 authenticated and log out. 34 00:01:42,000 --> 00:01:45,840 Or you'll want a way for users of your website, managers of your website 35 00:01:45,840 --> 00:01:48,360 to be able to add data to it, update existing information, 36 00:01:48,360 --> 00:01:51,040 add information to any of your various tables. 37 00:01:51,040 --> 00:01:53,790 Or you might have more complicated relationships between your data 38 00:01:53,790 --> 00:01:54,930 that you want to manage. 39 00:01:54,930 --> 00:01:57,210 And if you are writing a web application in Flask, 40 00:01:57,210 --> 00:01:59,418 you would need to build all of that out for yourself. 41 00:01:59,418 --> 00:02:03,630 You would need to design pages that let people add data to your database, 42 00:02:03,630 --> 00:02:06,525 have separate pages and let people edit them or remove that data. 43 00:02:06,525 --> 00:02:09,150 And all of that would be manual work that you would need to do. 44 00:02:09,150 --> 00:02:12,330 But because this is so common, there are other web frameworks out there 45 00:02:12,330 --> 00:02:14,440 that give you a little bit more out of the box. 46 00:02:14,440 --> 00:02:16,398 And so today what we're going to be introducing 47 00:02:16,398 --> 00:02:19,602 is a new web framework that looks similar to Flask in spirit 48 00:02:19,602 --> 00:02:22,560 but it is much heavier weight, has a lot more features and capabilities 49 00:02:22,560 --> 00:02:24,990 that it has built into it, known as Django. 50 00:02:24,990 --> 00:02:28,290 And we're going to be exploring Django and some of the features 51 00:02:28,290 --> 00:02:31,230 that it has to offer when it comes towards building more complex web 52 00:02:31,230 --> 00:02:31,869 applications. 53 00:02:31,869 --> 00:02:33,660 And our goal as we look through all of this 54 00:02:33,660 --> 00:02:36,287 is that we'll start by looking at simple web applications 55 00:02:36,287 --> 00:02:39,120 where it seems like we're doing the same things that Flask could do, 56 00:02:39,120 --> 00:02:41,530 but it seems like it's just a little more complicated. 57 00:02:41,530 --> 00:02:43,830 But we'll soon see how using a framework like Django, 58 00:02:43,830 --> 00:02:46,020 we can actually take advantage of the leverage 59 00:02:46,020 --> 00:02:50,250 the Django gives us in order to add a whole lot of additional features 60 00:02:50,250 --> 00:02:52,710 and complexities and nuances to our application that 61 00:02:52,710 --> 00:02:55,860 would take much more time to build out for yourself by hand using something 62 00:02:55,860 --> 00:02:59,980 like Flask and that Django just makes much simpler for us to build. 63 00:02:59,980 --> 00:03:03,972 So let's go ahead and get started by building our first Django application. 64 00:03:03,972 --> 00:03:06,180 And so once you've install Django, and in this course 65 00:03:06,180 --> 00:03:08,430 we're going to be using the latest version of Django-- 66 00:03:08,430 --> 00:03:11,044 Django 2-- which was released pretty recently, 67 00:03:11,044 --> 00:03:13,210 you'll run a command that looks something like this. 68 00:03:13,210 --> 00:03:15,540 You'll get access to a command called Django Admin. 69 00:03:15,540 --> 00:03:17,760 And Django divides all of its web applications 70 00:03:17,760 --> 00:03:19,470 into what are called projects. 71 00:03:19,470 --> 00:03:22,350 So think of a project as just your entire web 72 00:03:22,350 --> 00:03:25,709 application that might be composed of different parts, which we'll soon see. 73 00:03:25,709 --> 00:03:27,750 But to create a new project, you'll run a command 74 00:03:27,750 --> 00:03:31,830 like django-admin, which is the name of the command, startproject to create 75 00:03:31,830 --> 00:03:34,890 a brand new project, followed by the name of the project 76 00:03:34,890 --> 00:03:36,250 that you want to create. 77 00:03:36,250 --> 00:03:39,090 So let's take a look at an example of that. 78 00:03:39,090 --> 00:03:42,990 If I go under the command line and I type 79 00:03:42,990 --> 00:03:48,000 django-admin startproject and I'll just call it mysite, for instance. 80 00:03:48,000 --> 00:03:50,310 What that's going to do is it's going to create 81 00:03:50,310 --> 00:03:54,030 a new directory for me called mysite. 82 00:03:54,030 --> 00:03:58,050 And if I cd into it, I see that I have a file called manage.py 83 00:03:58,050 --> 00:04:01,200 and another directory inside of it also called mysite. 84 00:04:01,200 --> 00:04:04,882 And if I go into that directory, I have a whole bunch of other files 85 00:04:04,882 --> 00:04:06,340 that have just been created for me. 86 00:04:06,340 --> 00:04:10,650 I didn't create any of these files-- init.py, settings, URLs, and WSGI. 87 00:04:10,650 --> 00:04:14,310 These are just files that are created for me by default when Django first 88 00:04:14,310 --> 00:04:16,440 creates a project for me. 89 00:04:16,440 --> 00:04:19,560 So what are these files and what do they mean? 90 00:04:19,560 --> 00:04:25,470 Well, this init.py file tells us that the mysite directory 91 00:04:25,470 --> 00:04:26,940 is a Python package. 92 00:04:26,940 --> 00:04:29,132 And a Python package is just a collection 93 00:04:29,132 --> 00:04:30,840 of a bunch of different Python files that 94 00:04:30,840 --> 00:04:32,520 are grouped together for some purpose. 95 00:04:32,520 --> 00:04:35,280 And Django was really built on the idea of these Python packages 96 00:04:35,280 --> 00:04:37,696 where we're going to end up with multiple different Python 97 00:04:37,696 --> 00:04:39,725 packages, multiple different groups of files 98 00:04:39,725 --> 00:04:41,850 that each are serving a slightly different purpose. 99 00:04:41,850 --> 00:04:44,700 And Django is going to allow us to have a web application that 100 00:04:44,700 --> 00:04:47,190 uses and integrates with all of these. 101 00:04:47,190 --> 00:04:49,770 Manage.py is a particularly important file. 102 00:04:49,770 --> 00:04:51,720 You won't need to edit manage.py. 103 00:04:51,720 --> 00:04:54,180 But manage.py is going to be a Python script 104 00:04:54,180 --> 00:04:58,770 that you can use in order to perform some very useful operations on your web 105 00:04:58,770 --> 00:05:00,270 application as you're working on it. 106 00:05:00,270 --> 00:05:03,590 And we'll see multiple examples of using manage.py later. 107 00:05:03,590 --> 00:05:05,700 Settings.py is a file that's created for us 108 00:05:05,700 --> 00:05:08,310 that just has all of the settings for our web application, 109 00:05:08,310 --> 00:05:11,100 things like what time zone the application should be in 110 00:05:11,100 --> 00:05:15,590 or what other applications are installed within our project, for instance. 111 00:05:15,590 --> 00:05:18,450 Or what sort of database do we want to use with our application. 112 00:05:18,450 --> 00:05:21,040 These are all things that are defined in the settings. 113 00:05:21,040 --> 00:05:22,640 urls.py is interesting. 114 00:05:22,640 --> 00:05:24,320 We'll take it urls.py in a moment. 115 00:05:24,320 --> 00:05:27,080 But urls is going to do is act as the file that 116 00:05:27,080 --> 00:05:30,470 takes care of determining what URLs or what 117 00:05:30,470 --> 00:05:34,190 routes the user can go to when they visit a web application. 118 00:05:34,190 --> 00:05:37,250 So in a Flask, if you recall, at the top of every function, 119 00:05:37,250 --> 00:05:40,100 how did we indicate how to get there? 120 00:05:40,100 --> 00:05:42,980 How did we in associate functions with what URL 121 00:05:42,980 --> 00:05:45,830 the user had to type into the web browser? 122 00:05:45,830 --> 00:05:46,330 Yeah. 123 00:05:46,330 --> 00:05:48,000 We used this route decorator. 124 00:05:48,000 --> 00:05:51,370 We say, atapp.route followed by the route that we wanted to go to. 125 00:05:51,370 --> 00:05:53,590 And when a user typed in that route and press Return, 126 00:05:53,590 --> 00:05:55,423 that would be associated with that function. 127 00:05:55,423 --> 00:05:57,590 And every function had the route on top of it 128 00:05:57,590 --> 00:05:59,290 that corresponded with that function. 129 00:05:59,290 --> 00:06:01,720 What Django does is it separates out this functionality 130 00:06:01,720 --> 00:06:03,380 into two different places. 131 00:06:03,380 --> 00:06:07,690 So we have one file called urls.py which only contains the URLs 132 00:06:07,690 --> 00:06:08,860 that people can go to. 133 00:06:08,860 --> 00:06:11,950 And it associates those URLs with the particular functions 134 00:06:11,950 --> 00:06:15,310 that are ultimately going to run in order to render the response that we 135 00:06:15,310 --> 00:06:17,040 want to give back to the user. 136 00:06:17,040 --> 00:06:19,450 Wsgi.py, you don't need to worry about too much. 137 00:06:19,450 --> 00:06:23,170 But if you were to ever take a Django web application and deploy it to a web 138 00:06:23,170 --> 00:06:26,230 server, for instance, so that it could live and hosted online. 139 00:06:26,230 --> 00:06:29,290 wsgi.py is a common way to allow that to happen. 140 00:06:29,290 --> 00:06:33,110 And all of that, of course, is stored inside of this project name directory. 141 00:06:33,110 --> 00:06:36,190 So now that we have all of that set up, the next step 142 00:06:36,190 --> 00:06:39,280 is to create what's called a Django application. 143 00:06:39,280 --> 00:06:42,340 So a Django project is our big picture project 144 00:06:42,340 --> 00:06:45,490 that contains all of the files needed for our website. 145 00:06:45,490 --> 00:06:50,230 And a Django project consists of one or more Django applications 146 00:06:50,230 --> 00:06:53,110 or apps where each one of these individual apps 147 00:06:53,110 --> 00:06:57,130 usually just serves a particular purpose or has some particular function. 148 00:06:57,130 --> 00:06:59,230 Django has some built in apps for us. 149 00:06:59,230 --> 00:07:01,600 And what we're going to do is create an app 150 00:07:01,600 --> 00:07:05,230 within this project that's going to handle the routes that we care about 151 00:07:05,230 --> 00:07:06,110 in this case. 152 00:07:06,110 --> 00:07:08,590 And for this simple project, we're just going 153 00:07:08,590 --> 00:07:10,570 to create a single app that's going to allow 154 00:07:10,570 --> 00:07:12,520 us to take care of some basic routing, very 155 00:07:12,520 --> 00:07:14,890 similar to what Flask allowed us to do. 156 00:07:14,890 --> 00:07:21,370 So to create an app, what we're going to do is inside the mysite directory, 157 00:07:21,370 --> 00:07:24,710 we're going to go and we see this manage.py file, 158 00:07:24,710 --> 00:07:27,970 which is the file that allows us to run some basic commands on this Django 159 00:07:27,970 --> 00:07:28,810 project. 160 00:07:28,810 --> 00:07:33,999 And the command here is a python manage.py startapp 161 00:07:33,999 --> 00:07:36,290 followed by the name of the app that we want to create. 162 00:07:36,290 --> 00:07:38,665 So let's create a basic Hello World app, much like we did 163 00:07:38,665 --> 00:07:40,540 when we created our first Flask app. 164 00:07:40,540 --> 00:07:42,970 And we'll call this app hello. 165 00:07:42,970 --> 00:07:45,640 And so what that's going to do is give us a new directory 166 00:07:45,640 --> 00:07:48,940 called hello inside of mysite. 167 00:07:48,940 --> 00:07:51,774 And inside of this hello directory are a whole bunch of other files. 168 00:07:51,774 --> 00:07:53,815 And we won't worry too much about these just yet. 169 00:07:53,815 --> 00:07:55,210 But we'll get to them soon. 170 00:07:55,210 --> 00:07:57,700 And so now, let's actually edit some of these files 171 00:07:57,700 --> 00:08:00,310 and see what's going on inside of all of this. 172 00:08:00,310 --> 00:08:04,660 So hello is the name of the app that we've just created, this hello app. 173 00:08:04,660 --> 00:08:10,840 And inside of views.py, this is analogous to what application.py 174 00:08:10,840 --> 00:08:12,550 was inside of our Flask application. 175 00:08:12,550 --> 00:08:14,466 It's the place where we're going to be writing 176 00:08:14,466 --> 00:08:17,770 the code that ultimately decides what the user sees 177 00:08:17,770 --> 00:08:19,640 when they go to a particular route. 178 00:08:19,640 --> 00:08:22,420 And so in this case, I'm going to define an index 179 00:08:22,420 --> 00:08:24,490 function much like I have before. 180 00:08:24,490 --> 00:08:28,420 And in Django, all of our view functions are going to take as an argument 181 00:08:28,420 --> 00:08:30,400 this object called request. 182 00:08:30,400 --> 00:08:32,807 And you may have seen something like this in Flask 183 00:08:32,807 --> 00:08:35,140 where we had a request object that contained information 184 00:08:35,140 --> 00:08:38,230 like what were the arguments that were passed into the request 185 00:08:38,230 --> 00:08:43,100 and what sorts of cookies, for instance, might be associated with that request. 186 00:08:43,100 --> 00:08:46,690 And so this request objects are as much the same behavior in this case. 187 00:08:46,690 --> 00:08:49,300 And all our index function is going to do right now 188 00:08:49,300 --> 00:08:55,060 is return some basic HTTP response that says hello, for instance. 189 00:08:55,060 --> 00:08:57,790 And so in Django that's going to look something like this, 190 00:08:57,790 --> 00:08:59,200 something like hello world. 191 00:08:59,200 --> 00:09:03,710 And of course, HTTP response is not an object that we've created. 192 00:09:03,710 --> 00:09:05,140 It's something built into Django. 193 00:09:05,140 --> 00:09:07,405 So in order to use it, I'm going to have to import it. 194 00:09:07,405 --> 00:09:11,356 So from django.http import http response. 195 00:09:11,356 --> 00:09:14,230 So immediately what we're noticing is that even just to get something 196 00:09:14,230 --> 00:09:18,230 as basic as hello world, it looks like there is a lot more complexity involved 197 00:09:18,230 --> 00:09:18,730 in it. 198 00:09:18,730 --> 00:09:20,938 Soon the reason for that complexity will become clear 199 00:09:20,938 --> 00:09:24,700 as we begin to build more sophisticated, more complex web applications. 200 00:09:24,700 --> 00:09:28,570 But for now, try to focus on drawing the parallels and analogies between this 201 00:09:28,570 --> 00:09:33,420 and Flask rather than try to worry about all the specific syntax. 202 00:09:33,420 --> 00:09:36,990 So we've added an index function that says hello world. 203 00:09:36,990 --> 00:09:41,430 Is this going to be enough now for someone to be able to go to a URL 204 00:09:41,430 --> 00:09:44,164 and see hello world appear in their web browser? 205 00:09:44,164 --> 00:09:46,830 What are we missing, at least if you're comparing this to Flask? 206 00:09:46,830 --> 00:09:49,626 207 00:09:49,626 --> 00:09:51,024 AUDIENCE: HTML, or-- 208 00:09:51,024 --> 00:09:53,170 SPEAKER 1: There is no HTML, certainly. 209 00:09:53,170 --> 00:09:56,830 And so later on what we'll see is we'll modify our view slightly so that we 210 00:09:56,830 --> 00:09:59,230 can return a fully fledged HTML file. 211 00:09:59,230 --> 00:10:01,570 But even if we were to add HTML here, what else 212 00:10:01,570 --> 00:10:05,780 is missing if you think about how this file compares to a file in Flask 213 00:10:05,780 --> 00:10:06,490 for instance? 214 00:10:06,490 --> 00:10:07,369 AUDIENCE: A route. 215 00:10:07,369 --> 00:10:08,410 SPEAKER 1: A route, yeah. 216 00:10:08,410 --> 00:10:11,217 I didn't specify at what URL the user is going to. 217 00:10:11,217 --> 00:10:13,300 Is it just the empty route like the default slash? 218 00:10:13,300 --> 00:10:15,841 Or is it something else they have to type in the URL in order 219 00:10:15,841 --> 00:10:16,960 to get to this function? 220 00:10:16,960 --> 00:10:19,090 I haven't defined any of that yet. 221 00:10:19,090 --> 00:10:25,660 And so what I'm going to do inside of my app is create a new file. 222 00:10:25,660 --> 00:10:28,600 And we're going to call it urls.py. 223 00:10:28,600 --> 00:10:33,250 Notice this is a different urls.py from the other urls.py we had. 224 00:10:33,250 --> 00:10:37,000 The first urls.py, which is inside the mysite directory, 225 00:10:37,000 --> 00:10:39,520 is the project's URLs file. 226 00:10:39,520 --> 00:10:42,220 Whereas this urls.py file that I just created 227 00:10:42,220 --> 00:10:45,460 is a urls.py file specific to this particular app. 228 00:10:45,460 --> 00:10:49,202 In this case, this Django project, I've only created one app inside of it. 229 00:10:49,202 --> 00:10:51,160 But you'll see, as project start to get larger, 230 00:10:51,160 --> 00:10:54,982 that oftentimes Django projects will be composed of multiple different apps, 231 00:10:54,982 --> 00:10:56,440 each of which has their own routes. 232 00:10:56,440 --> 00:10:59,710 And often this is a good way to separate different types of functionality 233 00:10:59,710 --> 00:11:02,920 into different places just to keep your entire project organized 234 00:11:02,920 --> 00:11:04,474 as projects tend to get big. 235 00:11:04,474 --> 00:11:06,640 And separating things out into separate applications 236 00:11:06,640 --> 00:11:09,610 helps to keep things organized, makes those individual apps reusable 237 00:11:09,610 --> 00:11:13,090 if need be, and can ultimately be a good organizational tool for a Django 238 00:11:13,090 --> 00:11:14,350 project. 239 00:11:14,350 --> 00:11:16,960 So inside of urls.py, we're going to need 240 00:11:16,960 --> 00:11:19,570 to include some code that looks something like this. 241 00:11:19,570 --> 00:11:22,690 We're going to import this path variable. 242 00:11:22,690 --> 00:11:25,810 And also, we're going to import from dot, 243 00:11:25,810 --> 00:11:28,780 in other words, the current directory, the current package, 244 00:11:28,780 --> 00:11:30,730 we're going to import our views. 245 00:11:30,730 --> 00:11:33,697 So we were just editing views.py over here 246 00:11:33,697 --> 00:11:36,280 where we defined this function called index inside of it which 247 00:11:36,280 --> 00:11:37,840 returns hello world. 248 00:11:37,840 --> 00:11:40,870 And now inside of urls.py I'm going to need 249 00:11:40,870 --> 00:11:44,980 to tell Django that I want to associate a particular URL 250 00:11:44,980 --> 00:11:46,630 with a particular view. 251 00:11:46,630 --> 00:11:51,410 And the way Django does that is through a variable called urlpatterns. 252 00:11:51,410 --> 00:11:55,210 And urlpatterns is just going to be a list of all of the URLs 253 00:11:55,210 --> 00:11:57,620 that are supported by this particular app. 254 00:11:57,620 --> 00:12:01,790 So in this case, I'm going to say, path empty string meaning empty route. 255 00:12:01,790 --> 00:12:02,920 Just user type slash. 256 00:12:02,920 --> 00:12:04,836 They don't need to have anything after the url 257 00:12:04,836 --> 00:12:06,620 in order to get to this particular view. 258 00:12:06,620 --> 00:12:09,880 And then I need to associate it with what function, what view function, 259 00:12:09,880 --> 00:12:13,570 do I actually want to run when someone goes to this empty route. 260 00:12:13,570 --> 00:12:16,540 And so in this case, it's going to be views.index 261 00:12:16,540 --> 00:12:19,960 because views is this Python module that I just imported, 262 00:12:19,960 --> 00:12:22,580 this views.py file that I have here. 263 00:12:22,580 --> 00:12:25,840 And the name of the function inside of views is called index. 264 00:12:25,840 --> 00:12:28,420 And so I'm saying, when the user goes to this empty route, 265 00:12:28,420 --> 00:12:33,890 here's what you should run, go to the views file, and run the index function. 266 00:12:33,890 --> 00:12:35,140 And here is views.py. 267 00:12:35,140 --> 00:12:36,730 Here's that index function. 268 00:12:36,730 --> 00:12:40,430 And it returns an http response, hello world. 269 00:12:40,430 --> 00:12:41,710 So that's what that's doing. 270 00:12:41,710 --> 00:12:45,610 And we're almost ready to make this application actually 271 00:12:45,610 --> 00:12:49,060 work when we run this project, except we're missing one last piece, which 272 00:12:49,060 --> 00:12:53,350 is that when the Django project starts up and starts looking for URLs, 273 00:12:53,350 --> 00:12:57,640 it's only going to look at the URLs file of the entire project, 274 00:12:57,640 --> 00:13:00,790 this mysite urls.py file which you'll notice already 275 00:13:00,790 --> 00:13:02,979 has a whole bunch of code in here already. 276 00:13:02,979 --> 00:13:05,270 And we'll take a look at some of what this means later. 277 00:13:05,270 --> 00:13:09,460 But what I need to do is this last final step is to inside of the projects 278 00:13:09,460 --> 00:13:14,170 urls.py file, link it to my app's urls.py file. 279 00:13:14,170 --> 00:13:17,080 So this was the urls.py file that was created for me when I first 280 00:13:17,080 --> 00:13:18,660 created this project. 281 00:13:18,660 --> 00:13:21,824 And the hello urls.py file is the file I just created. 282 00:13:21,824 --> 00:13:23,990 And I need to tell these two files about each other, 283 00:13:23,990 --> 00:13:29,230 make sure my project file know that my application's URL file exists. 284 00:13:29,230 --> 00:13:33,820 And the syntax for doing that is a little unclear at first. 285 00:13:33,820 --> 00:13:37,060 But what we'll do is add another path that 286 00:13:37,060 --> 00:13:40,480 just says if someone goes to empty string the empty route, 287 00:13:40,480 --> 00:13:46,640 we're going to just route them to the hello app's URLs 288 00:13:46,640 --> 00:13:48,660 and have hello take care of all of that. 289 00:13:48,660 --> 00:13:51,590 And so the reason you might do something like this is that oftentimes 290 00:13:51,590 --> 00:13:53,930 if you separated things into multiple different apps 291 00:13:53,930 --> 00:13:57,260 and you want those different apps to be handled by multiple different routes, 292 00:13:57,260 --> 00:13:58,260 for instance. 293 00:13:58,260 --> 00:14:02,300 You might say, later, something like if someone goes to the app one route 294 00:14:02,300 --> 00:14:06,470 and goes to app1/foo or app1/bar, then you might 295 00:14:06,470 --> 00:14:09,230 want to direct them to app1'd URLs. 296 00:14:09,230 --> 00:14:14,030 And if someone likewise goes to app2 slash something, 297 00:14:14,030 --> 00:14:16,560 you might want to route them to some second app's URLs. 298 00:14:16,560 --> 00:14:19,640 And so this file is the first place where 299 00:14:19,640 --> 00:14:22,610 URLs are dispatched from, that when someone goes to URL, 300 00:14:22,610 --> 00:14:24,030 we look through this file. 301 00:14:24,030 --> 00:14:26,488 And if it turns out we should send them one way or another, 302 00:14:26,488 --> 00:14:30,540 then we'll send them to potentially a different URLs file after that. 303 00:14:30,540 --> 00:14:33,160 But for now, this is all we need to say, just direct 304 00:14:33,160 --> 00:14:35,556 the person to the hello app's URLs. 305 00:14:35,556 --> 00:14:36,180 Yeah, question? 306 00:14:36,180 --> 00:14:39,540 AUDIENCE: How does it know where [INAUDIBLE] parallel 307 00:14:39,540 --> 00:14:42,420 to mysite directory [INAUDIBLE]. 308 00:14:42,420 --> 00:14:43,590 SPEAKER 1: So good question. 309 00:14:43,590 --> 00:14:46,250 The question was, how does the application know 310 00:14:46,250 --> 00:14:48,650 where the hello module is. 311 00:14:48,650 --> 00:14:50,390 When we're running the application, we're 312 00:14:50,390 --> 00:14:53,780 going to be running the application from the parent mysite directory 313 00:14:53,780 --> 00:14:57,890 so that the parent directory can see all of the individual Python packages. 314 00:14:57,890 --> 00:14:58,980 Great question. 315 00:14:58,980 --> 00:14:59,480 All right. 316 00:14:59,480 --> 00:15:01,271 So after all that complexity, we're finally 317 00:15:01,271 --> 00:15:04,830 ready to actually go ahead and run the application. 318 00:15:04,830 --> 00:15:07,570 And the way we run the application is again using manage.py. 319 00:15:07,570 --> 00:15:10,340 We do python manage.py high and there is a special command 320 00:15:10,340 --> 00:15:13,550 called run server such that when we type run server, 321 00:15:13,550 --> 00:15:15,530 that's going to start up this application. 322 00:15:15,530 --> 00:15:18,200 Here's the URL where it lives at. 323 00:15:18,200 --> 00:15:21,330 We'll go ahead and copy that, paste it into a web browser. 324 00:15:21,330 --> 00:15:23,270 And now we see hello world. 325 00:15:23,270 --> 00:15:25,640 So that was our very first web application in Django. 326 00:15:25,640 --> 00:15:26,820 It seemed quite complicated. 327 00:15:26,820 --> 00:15:29,111 But we'll soon see in just a moment how we can actually 328 00:15:29,111 --> 00:15:32,300 use the additional features given to us by Django 329 00:15:32,300 --> 00:15:35,060 in order to make our application a whole lot more powerful. 330 00:15:35,060 --> 00:15:38,440 But before we move on, questions about anything we've gone ever so far? 331 00:15:38,440 --> 00:15:41,320 332 00:15:41,320 --> 00:15:41,820 OK. 333 00:15:41,820 --> 00:15:45,079 So what I thought we'd do now is take a look at that Flight application 334 00:15:45,079 --> 00:15:47,370 that we created way back in one of the earlier lectures 335 00:15:47,370 --> 00:15:50,070 when we were first introducing Flask and databases where 336 00:15:50,070 --> 00:15:52,470 we wanted to create an application that could maintain 337 00:15:52,470 --> 00:15:53,845 flights and passengers and so on. 338 00:15:53,845 --> 00:15:55,844 And we'll take a look at how we can quite easily 339 00:15:55,844 --> 00:15:57,930 build this application in Django and actually 340 00:15:57,930 --> 00:16:01,410 make it even more featured than our Flask version using potentially 341 00:16:01,410 --> 00:16:03,800 fewer lines of code, in fact. 342 00:16:03,800 --> 00:16:07,050 And so what I'm going to do is I've already created 343 00:16:07,050 --> 00:16:09,480 a basic application called airline. 344 00:16:09,480 --> 00:16:13,800 And all this airline Django project does is 345 00:16:13,800 --> 00:16:17,820 it has an app within it called Flights. 346 00:16:17,820 --> 00:16:20,580 Inside of Flights is a URLs file that looks almost exactly 347 00:16:20,580 --> 00:16:22,620 like the one we just created that just directs 348 00:16:22,620 --> 00:16:25,410 the empty route to the views.index. 349 00:16:25,410 --> 00:16:29,850 And inside of my views file, I return an http response that just says Flights. 350 00:16:29,850 --> 00:16:32,220 And so all my application does right now is 351 00:16:32,220 --> 00:16:35,100 sort of what we just created in our hello world example, 352 00:16:35,100 --> 00:16:40,840 is that if I run the server and go to this URL, 353 00:16:40,840 --> 00:16:43,270 it just says Flights instead of hello world in this case. 354 00:16:43,270 --> 00:16:46,240 But what we want to do now is start to set up 355 00:16:46,240 --> 00:16:48,070 the database for this application. 356 00:16:48,070 --> 00:16:51,880 And so Django was designed with wanting to interact with data in mind. 357 00:16:51,880 --> 00:16:55,070 And so it makes it very easy for us to do something like this. 358 00:16:55,070 --> 00:16:58,450 So what I'm going to introduce now is this models.py file 359 00:16:58,450 --> 00:17:00,576 that's sitting inside of my Flights application. 360 00:17:00,576 --> 00:17:01,450 Right now it's empty. 361 00:17:01,450 --> 00:17:04,420 And Django by default just says, create your models here. 362 00:17:04,420 --> 00:17:06,400 This is the place where I'm going to start 363 00:17:06,400 --> 00:17:10,780 to define the classes that are going to define the types of data 364 00:17:10,780 --> 00:17:13,510 that I want to be able to store inside of my database 365 00:17:13,510 --> 00:17:15,500 for this particular application. 366 00:17:15,500 --> 00:17:17,349 And so, this is very analogous to what we 367 00:17:17,349 --> 00:17:20,307 were doing with Flask SQL Alchemy, which was a separate package that we 368 00:17:20,307 --> 00:17:23,619 had to install in order to allow us to do these same sorts of things. 369 00:17:23,619 --> 00:17:26,895 Django has this all built in into its own ORM which functions very similarly. 370 00:17:26,895 --> 00:17:29,770 So you'll see a lot of parallels, although the syntax is a little bit 371 00:17:29,770 --> 00:17:30,800 different. 372 00:17:30,800 --> 00:17:33,850 And so if we want to create a model for representing a flight, 373 00:17:33,850 --> 00:17:40,860 we might define a class called flight which is going to be a type of model. 374 00:17:40,860 --> 00:17:44,921 And if we recall from last time, what properties did a flight need to have? 375 00:17:44,921 --> 00:17:47,170 What stuff did we include inside of our flights table? 376 00:17:47,170 --> 00:17:50,523 377 00:17:50,523 --> 00:17:52,439 AUDIENCE: Origin and destination. 378 00:17:52,439 --> 00:17:53,860 SPEAKER 1: Origin and destination. 379 00:17:53,860 --> 00:17:54,360 Great. 380 00:17:54,360 --> 00:17:59,290 So our origin, for now we're just going to represent as a character field. 381 00:17:59,290 --> 00:18:02,580 And we'll say the maximum length is going to be 64. 382 00:18:02,580 --> 00:18:04,406 Not all databases require a maximum length. 383 00:18:04,406 --> 00:18:06,780 But for some databases, it can often be helpful to do so. 384 00:18:06,780 --> 00:18:09,904 So if you know that there is a bound upon the length of a particular field, 385 00:18:09,904 --> 00:18:12,840 that's often good design practice to enforce that in there. 386 00:18:12,840 --> 00:18:16,080 I believe that there are no cities that are longer than 64 characters. 387 00:18:16,080 --> 00:18:19,345 So that feels like a reasonable limit to place on the origin of a flight. 388 00:18:19,345 --> 00:18:22,470 For a destination, that's likewise going to be a character field that we'll 389 00:18:22,470 --> 00:18:26,250 say has the maximum length of 64. 390 00:18:26,250 --> 00:18:29,520 And finally, we might also add a duration field 391 00:18:29,520 --> 00:18:31,410 that is going to be an integer field. 392 00:18:31,410 --> 00:18:33,660 And that is going to represent how long the flight is. 393 00:18:33,660 --> 00:18:35,285 And I could do other things, certainly. 394 00:18:35,285 --> 00:18:38,670 And Django comes in with all of these built in types of fields, so character 395 00:18:38,670 --> 00:18:42,300 fields, integer fields, Boolean fields, and other types of fields 396 00:18:42,300 --> 00:18:46,260 that map to different types of data inside of a SQL database, for instance. 397 00:18:46,260 --> 00:18:48,390 But this will be quite simply a basic flight 398 00:18:48,390 --> 00:18:52,920 class that is going to represent origins and destinations and durations. 399 00:18:52,920 --> 00:18:57,360 And so now what we're going to do is introduce the concept of migrations. 400 00:18:57,360 --> 00:19:00,960 And so what will often happen is you build a web application is very rarely 401 00:19:00,960 --> 00:19:04,590 is it the case that you will, when you first start building the application, 402 00:19:04,590 --> 00:19:08,250 define all of the tables exactly the way that you like them with all the columns 403 00:19:08,250 --> 00:19:09,092 that you want. 404 00:19:09,092 --> 00:19:11,550 Because usually you'll start out with some basic framework. 405 00:19:11,550 --> 00:19:14,997 But as your application starts to grow, as people start to use it, 406 00:19:14,997 --> 00:19:16,830 as you start to want to add features, you'll 407 00:19:16,830 --> 00:19:19,212 want to make modifications to your database. 408 00:19:19,212 --> 00:19:20,670 You're going to want to add tables. 409 00:19:20,670 --> 00:19:23,100 You're going to want to modify the columns in those tables 410 00:19:23,100 --> 00:19:25,360 or modify the relationships between them. 411 00:19:25,360 --> 00:19:27,750 And it would be quite tedious if every time you 412 00:19:27,750 --> 00:19:29,620 wanted to make a change to your database, 413 00:19:29,620 --> 00:19:32,730 you would need to not only change this sort of code, this model code that 414 00:19:32,730 --> 00:19:36,900 defines your classes, but also likewise actually run 415 00:19:36,900 --> 00:19:39,990 the the like Alter Table commands in SQL on your database 416 00:19:39,990 --> 00:19:42,120 in order to actually make those changes happen. 417 00:19:42,120 --> 00:19:44,940 What Django does is it uses something called migrations 418 00:19:44,940 --> 00:19:46,590 to solve that problem for us. 419 00:19:46,590 --> 00:19:48,810 What Django is going to do is automatically 420 00:19:48,810 --> 00:19:53,820 detect any time we make a change to our models.py file and to automatically 421 00:19:53,820 --> 00:19:57,270 generate the SQL code necessary to run on our database 422 00:19:57,270 --> 00:20:00,420 in order to allow for those changes to happen inside of our database. 423 00:20:00,420 --> 00:20:03,640 And so I'll show you what that looks like. 424 00:20:03,640 --> 00:20:05,765 So what we're going to do is-- 425 00:20:05,765 --> 00:20:09,051 oh, and before we can do this, there is one other configuration step 426 00:20:09,051 --> 00:20:12,300 that we just need to take, which is that we need to make sure that this Django 427 00:20:12,300 --> 00:20:15,220 project knows about these models, that my project know 428 00:20:15,220 --> 00:20:17,510 is that this application exists and has these models. 429 00:20:17,510 --> 00:20:20,580 And the way that I do that is by going into the settings file 430 00:20:20,580 --> 00:20:25,100 for the application and going to this installed apps 431 00:20:25,100 --> 00:20:26,990 variable, which is a list of all of the apps 432 00:20:26,990 --> 00:20:29,420 that are installed on this Django project. 433 00:20:29,420 --> 00:20:32,150 There are already a whole bunch of apps in here. 434 00:20:32,150 --> 00:20:34,044 These apps just happen to be built in apps 435 00:20:34,044 --> 00:20:35,585 into Django that serve easy purposes. 436 00:20:35,585 --> 00:20:38,030 So we have an admin app, which we'll look at later, 437 00:20:38,030 --> 00:20:40,080 an authentication app which we'll look at later, 438 00:20:40,080 --> 00:20:44,510 and other apps that serve other purposes that many web projects might want. 439 00:20:44,510 --> 00:20:46,500 And we'll see examples of those later. 440 00:20:46,500 --> 00:20:48,380 But right now, we can just say that we have 441 00:20:48,380 --> 00:20:51,770 this Flights app that is installed. 442 00:20:51,770 --> 00:20:57,260 And the way to indicate that we actually have this app installed 443 00:20:57,260 --> 00:21:00,790 is to include flights.app.FlightsConfig. 444 00:21:00,790 --> 00:21:04,960 Reason being, inside of our flights directory here, 445 00:21:04,960 --> 00:21:08,980 we have inside of it apps.py which is a configuration file for the application. 446 00:21:08,980 --> 00:21:11,500 And inside of that is FlightsConfig, which 447 00:21:11,500 --> 00:21:14,014 is the class that defines the settings for the application. 448 00:21:14,014 --> 00:21:15,680 So no need to worry too much about that. 449 00:21:15,680 --> 00:21:18,138 But just know that we do need to insert this line here just 450 00:21:18,138 --> 00:21:21,160 to say this application is installed on this project. 451 00:21:21,160 --> 00:21:27,250 But what we really want to do now is to create the table for managing flights 452 00:21:27,250 --> 00:21:28,760 inside of our database. 453 00:21:28,760 --> 00:21:30,700 So what is that going to look like? 454 00:21:30,700 --> 00:21:35,590 What I'm going to do is, using this manage.py script yet again, 455 00:21:35,590 --> 00:21:39,760 I'm going to run python manage.py makemigrations. 456 00:21:39,760 --> 00:21:42,490 What python manage.py makemigrations is going to do 457 00:21:42,490 --> 00:21:45,880 is look through my model files, look for any changes that 458 00:21:45,880 --> 00:21:49,750 have been made to those model files, and automatically generate 459 00:21:49,750 --> 00:21:52,300 a migration, which is going to represent the changes that 460 00:21:52,300 --> 00:21:56,410 need to be made to the database in order to allow for these new changes 461 00:21:56,410 --> 00:21:59,240 that I've made to the model file to actually work. 462 00:21:59,240 --> 00:22:02,100 So I run python manage.py makemigrations. 463 00:22:02,100 --> 00:22:07,171 And what we see is that it's created this new file called 001_initial.py. 464 00:22:07,171 --> 00:22:08,920 And it said it's created the model Flight. 465 00:22:08,920 --> 00:22:11,890 It's detected that I've added this new Flight model. 466 00:22:11,890 --> 00:22:15,460 And now it's telling me that it's now been created. 467 00:22:15,460 --> 00:22:19,960 So what's inside of this 001_initial.py file? 468 00:22:19,960 --> 00:22:22,660 Well, if we take a look at it, we see that it's 469 00:22:22,660 --> 00:22:24,820 created this class called migration. 470 00:22:24,820 --> 00:22:27,430 And inside of it, it's got all this information 471 00:22:27,430 --> 00:22:29,840 about things that should happen to the database. 472 00:22:29,840 --> 00:22:32,390 In other words, we should add an ID, origin, destination, 473 00:22:32,390 --> 00:22:35,720 and duration column to this new model that we're creating. 474 00:22:35,720 --> 00:22:38,770 And notice that I never actually specified in Django 475 00:22:38,770 --> 00:22:40,330 that I wanted an ID column. 476 00:22:40,330 --> 00:22:42,310 Django adds an ID column by default because it 477 00:22:42,310 --> 00:22:44,110 assumes if I'm creating a table, then it's 478 00:22:44,110 --> 00:22:46,150 going to have some sort of primary key column 479 00:22:46,150 --> 00:22:49,610 by which I can identify individual items in that table. 480 00:22:49,610 --> 00:22:52,114 So I don't need to explicitly create an ID column 481 00:22:52,114 --> 00:22:53,530 for every single one of my tables. 482 00:22:53,530 --> 00:22:56,120 Django takes care of that for me. 483 00:22:56,120 --> 00:23:01,300 So what would actually happen if I were to apply this migration to a database? 484 00:23:01,300 --> 00:23:04,456 Well, we can take a look at what that code would look like. 485 00:23:04,456 --> 00:23:07,330 You likely don't actually ever need to run this command unless you're 486 00:23:07,330 --> 00:23:08,720 curious to take a look at it. 487 00:23:08,720 --> 00:23:13,420 But what if I run python manage.py sqlmigrate followed by the name 488 00:23:13,420 --> 00:23:17,680 of the app, Flights, followed by the migration number 001, 489 00:23:17,680 --> 00:23:21,490 what I'm going to get is the SQL code that actually corresponds to this 490 00:23:21,490 --> 00:23:23,437 migration, migration 001. 491 00:23:23,437 --> 00:23:25,270 And what we see is it's a command that looks 492 00:23:25,270 --> 00:23:29,380 very similar to the types of things that we were doing way back when we first 493 00:23:29,380 --> 00:23:30,070 introduced SQL. 494 00:23:30,070 --> 00:23:31,720 It's the Create Table command. 495 00:23:31,720 --> 00:23:35,140 It's creating this table that has an ID column that's a primary key, 496 00:23:35,140 --> 00:23:38,104 has an origin column, a destination column, and a duration column. 497 00:23:38,104 --> 00:23:40,270 And that's all SQL code that I didn't need to write. 498 00:23:40,270 --> 00:23:43,390 It was generated for me by Django's migration system 499 00:23:43,390 --> 00:23:46,540 just by looking at what I said I wanted in my database 500 00:23:46,540 --> 00:23:49,850 and generating the code to run that for me automatically. 501 00:23:49,850 --> 00:23:53,200 And so now, if I want to apply this migration to the database, 502 00:23:53,200 --> 00:23:56,620 actually now creating the table inside of my database, 503 00:23:56,620 --> 00:23:59,982 I'm going to say python manage.py migrate. 504 00:23:59,982 --> 00:24:02,440 And what that did is it applied to all of these migrations, 505 00:24:02,440 --> 00:24:06,680 including some default Django ones, but it also applied this flights 506 00:24:06,680 --> 00:24:09,160 0001_initial migration. 507 00:24:09,160 --> 00:24:13,736 And now my database is going to have this table that represents flights. 508 00:24:13,736 --> 00:24:16,360 Questions about the migration system so far, before we move on? 509 00:24:16,360 --> 00:24:16,985 Yeah? 510 00:24:16,985 --> 00:24:19,210 AUDIENCE: How does it know what database to make changes to? 511 00:24:19,210 --> 00:24:20,293 SPEAKER 1: Great question. 512 00:24:20,293 --> 00:24:22,510 How does it know what database to make changes to? 513 00:24:22,510 --> 00:24:26,950 That's all defined inside of the settings for the application. 514 00:24:26,950 --> 00:24:29,200 And so if we go into the settings.py file 515 00:24:29,200 --> 00:24:32,950 and scroll down to this databases variable, what we'll see 516 00:24:32,950 --> 00:24:37,344 is that we've said that the engine for this database should be SQL Light. 517 00:24:37,344 --> 00:24:39,760 And SQL Light is just a slightly different version of SQL, 518 00:24:39,760 --> 00:24:43,180 much like PostgreSQL, that happens to store everything locally 519 00:24:43,180 --> 00:24:46,570 on a file instead of running separately on some server somewhere which 520 00:24:46,570 --> 00:24:48,430 makes it very useful for local testing. 521 00:24:48,430 --> 00:24:51,730 If you wanted to use PostgreSQL as we did in project one 522 00:24:51,730 --> 00:24:54,580 on a project in Django, you could change the engine 523 00:24:54,580 --> 00:24:57,930 to just be a PostgreSQL database, which Django supports. 524 00:24:57,930 --> 00:25:01,420 And in this case, we've just specified what the name of the databases is. 525 00:25:01,420 --> 00:25:04,840 In this case, it's db.sqlight 3 which happens 526 00:25:04,840 --> 00:25:08,650 to be a file that exists inside of my directory. 527 00:25:08,650 --> 00:25:11,085 But if you change this to a PostgreSQL database 528 00:25:11,085 --> 00:25:13,210 rather than providing a name here, you would likely 529 00:25:13,210 --> 00:25:16,880 specify the host where the database exists, the port on which it's on, 530 00:25:16,880 --> 00:25:20,320 and a username and password, much in the same way that you did in Project 1. 531 00:25:20,320 --> 00:25:23,260 But that's all configured inside of the settings file. 532 00:25:23,260 --> 00:25:25,840 Good question. 533 00:25:25,840 --> 00:25:29,750 So that database file now has the models that I've created. 534 00:25:29,750 --> 00:25:34,510 So let's go ahead and actually try and create some of these flights 535 00:25:34,510 --> 00:25:36,440 by looking at how that happens. 536 00:25:36,440 --> 00:25:39,400 And so what Django allows us to do is it gives us access 537 00:25:39,400 --> 00:25:40,630 to what's called a shell. 538 00:25:40,630 --> 00:25:43,030 So much like Python's interpreter, but that 539 00:25:43,030 --> 00:25:46,810 is tied into this Django application and lets us directly modify the database 540 00:25:46,810 --> 00:25:48,190 without too much effort. 541 00:25:48,190 --> 00:25:51,910 And so to run the shell, again I'm going to run python manage.py followed 542 00:25:51,910 --> 00:25:53,990 by the word shell. 543 00:25:53,990 --> 00:25:57,800 And now I'm inside of Django's shell, where I can run Python commands. 544 00:25:57,800 --> 00:26:01,790 And in particular, I'm going to say from flights.models-- 545 00:26:01,790 --> 00:26:04,310 remember I had a Python package called Flights, my app, 546 00:26:04,310 --> 00:26:06,560 inside of which was a file called models? 547 00:26:06,560 --> 00:26:09,360 I'm going to import Flight. 548 00:26:09,360 --> 00:26:12,860 And now what I'm going to do is I'm going to create a new flight. 549 00:26:12,860 --> 00:26:16,850 I'm going to say f is going to be equal to a flight whose origin is 550 00:26:16,850 --> 00:26:22,700 New York, whose destination is London, and whose duration is 415 minutes, 551 00:26:22,700 --> 00:26:24,020 for instance. 552 00:26:24,020 --> 00:26:25,900 And so I've now created that flight. 553 00:26:25,900 --> 00:26:30,140 And much like in SQL Alchemy where any time 554 00:26:30,140 --> 00:26:33,080 you add something or edit something, you need 555 00:26:33,080 --> 00:26:36,450 to save that change, likewise in Django you need to do the same thing. 556 00:26:36,450 --> 00:26:39,740 And the syntax for doing that is f.save. 557 00:26:39,740 --> 00:26:43,400 That is it effectively running that commit operation 558 00:26:43,400 --> 00:26:45,650 on a bunch of lines of SQL. 559 00:26:45,650 --> 00:26:47,990 And so f.save says actually save this new flight 560 00:26:47,990 --> 00:26:49,790 that I've created to the database. 561 00:26:49,790 --> 00:26:52,800 And now if I want to query for something in the database, 562 00:26:52,800 --> 00:26:58,510 if I just want a query for all flights, I can run Flight.objects.all. 563 00:26:58,510 --> 00:27:01,400 It's just a simple query that will get me all of the flights. 564 00:27:01,400 --> 00:27:05,210 And that returns to me a query set-- which you can think of as a fancy type 565 00:27:05,210 --> 00:27:07,340 of list that has additional features to it-- 566 00:27:07,340 --> 00:27:11,150 of all of my flights which right now is a list of just a single flight, 567 00:27:11,150 --> 00:27:13,900 this flight object 1. 568 00:27:13,900 --> 00:27:17,330 So this flight object 1 in parentheses, isn't very helpful 569 00:27:17,330 --> 00:27:20,720 for me to look at if I'm just looking at this in the Python terminal trying 570 00:27:20,720 --> 00:27:21,960 to understand it. 571 00:27:21,960 --> 00:27:25,280 And so very often what you'll see is that we'd like a better string 572 00:27:25,280 --> 00:27:27,350 representation of this flight. 573 00:27:27,350 --> 00:27:31,200 I'd like some easier way to look at this flight and understand what it means. 574 00:27:31,200 --> 00:27:36,290 And so what we can do is inside of our models file, 575 00:27:36,290 --> 00:27:41,002 I can add a underscore underscore STR function or a STR function. 576 00:27:41,002 --> 00:27:44,210 And what the STR function does, and this works for any class not just classes 577 00:27:44,210 --> 00:27:47,390 in Django, is it defines what the object should look 578 00:27:47,390 --> 00:27:49,264 like when it's printed out to a screen. 579 00:27:49,264 --> 00:27:51,680 And this will apply whether it's printed out to a terminal 580 00:27:51,680 --> 00:27:55,550 or even to an HTML page, as we'll see shortly. 581 00:27:55,550 --> 00:27:58,610 So if I want the string representation of the flight, 582 00:27:58,610 --> 00:28:02,810 I'm just going to say you should return the ID of the flight followed 583 00:28:02,810 --> 00:28:07,270 by the origin of the flight to the destination of the flight. 584 00:28:07,270 --> 00:28:09,810 And so I'm just going to return that. 585 00:28:09,810 --> 00:28:15,890 And so now if I go back into the shell, go to from Flights.models import flight 586 00:28:15,890 --> 00:28:20,230 and go Flight.objects.all, now I see that in the response that's 587 00:28:20,230 --> 00:28:24,020 come back to me, I have this Flight 1 New York to London. 588 00:28:24,020 --> 00:28:27,420 And I can very clearly see that that flight is there. 589 00:28:27,420 --> 00:28:33,590 And if I wanted to access it, I might do F equals Flight.objects.first 590 00:28:33,590 --> 00:28:35,100 to get me that first flight. 591 00:28:35,100 --> 00:28:37,670 F is now flight from New York to London. 592 00:28:37,670 --> 00:28:40,340 I can say F.origin, that's New York. 593 00:28:40,340 --> 00:28:43,280 F.destination, that's London. 594 00:28:43,280 --> 00:28:45,314 F.id is 1. 595 00:28:45,314 --> 00:28:46,730 And so I've now created my flight. 596 00:28:46,730 --> 00:28:51,400 If I want to delete that flight later, it's as simple as a F.delete. 597 00:28:51,400 --> 00:28:53,810 And that deletes the flight. 598 00:28:53,810 --> 00:28:55,163 Questions about anything so far? 599 00:28:55,163 --> 00:28:58,190 600 00:28:58,190 --> 00:28:58,690 All right. 601 00:28:58,690 --> 00:29:01,300 So now, we'll build on this idea of migrations, 602 00:29:01,300 --> 00:29:06,220 build on the idea of being able to change the contents of our database 603 00:29:06,220 --> 00:29:10,870 after we've already gone ahead and created some basic tables. 604 00:29:10,870 --> 00:29:16,330 Let's say that now rather than just defining the origin and destination 605 00:29:16,330 --> 00:29:19,900 as character fields where I type in text for the origin and destination, what 606 00:29:19,900 --> 00:29:22,480 would make more sense from a design perspective 607 00:29:22,480 --> 00:29:25,420 if I'm going about designing an application managed by an airline? 608 00:29:25,420 --> 00:29:26,770 If I want to maintain flights? 609 00:29:26,770 --> 00:29:29,560 Rather than a text field for the origin and destination, 610 00:29:29,560 --> 00:29:30,870 what might I use instead? 611 00:29:30,870 --> 00:29:31,370 Yeah? 612 00:29:31,370 --> 00:29:33,370 AUDIENCE: [INAUDIBLE] fields [INAUDIBLE].. 613 00:29:33,370 --> 00:29:35,161 SPEAKER 1: Yeah, something like an ID field 614 00:29:35,161 --> 00:29:37,380 where I actually have a table of airports, 615 00:29:37,380 --> 00:29:39,840 for instance, that maintains all the different airports. 616 00:29:39,840 --> 00:29:42,870 And my Flights table now rather than just be the text 617 00:29:42,870 --> 00:29:47,280 New York, the string New York as the origin could really be referencing 618 00:29:47,280 --> 00:29:49,679 the ID of some table of airports. 619 00:29:49,679 --> 00:29:51,720 So certainly that would be a good design decision 620 00:29:51,720 --> 00:29:53,470 that we could make if we're going to start 621 00:29:53,470 --> 00:29:55,680 to manage additional information about our airports. 622 00:29:55,680 --> 00:29:58,000 So let's take a look at that. 623 00:29:58,000 --> 00:29:59,480 So I go ahead and exit the shell. 624 00:29:59,480 --> 00:30:01,164 We'll go back into this models file. 625 00:30:01,164 --> 00:30:02,330 And I'll create a new class. 626 00:30:02,330 --> 00:30:04,913 We'll create a new class that's going to represent an airport. 627 00:30:04,913 --> 00:30:08,690 628 00:30:08,690 --> 00:30:13,790 And my airport is going to have a code which 629 00:30:13,790 --> 00:30:19,890 is just going to be that three character code that represents an airport. 630 00:30:19,890 --> 00:30:22,860 And it'll also have a city, that whatever city the airport is in. 631 00:30:22,860 --> 00:30:25,900 632 00:30:25,900 --> 00:30:29,710 And that's going to be a char field of max length 64. 633 00:30:29,710 --> 00:30:34,300 And if someone tries to access the string representation of an airport, 634 00:30:34,300 --> 00:30:39,820 I'm just going to return to them the name of the city 635 00:30:39,820 --> 00:30:44,320 and then in parentheses the code of that airport. 636 00:30:44,320 --> 00:30:46,660 And so define a new class called airport. 637 00:30:46,660 --> 00:30:49,751 And what other change do I now need to make? 638 00:30:49,751 --> 00:30:50,750 AUDIENCE: Change Flight. 639 00:30:50,750 --> 00:30:53,208 SPEAKER 1: Yeah, I need to change Flight now because origin 640 00:30:53,208 --> 00:30:55,440 and destination are no longer character fields. 641 00:30:55,440 --> 00:31:01,050 What origin is going to be instead is a models.Foreignkey. 642 00:31:01,050 --> 00:31:04,260 And so, it's going to be models.Foreignkey referencing 643 00:31:04,260 --> 00:31:07,950 some other class. 644 00:31:07,950 --> 00:31:10,200 And the class I'm going to reference is airport, 645 00:31:10,200 --> 00:31:12,033 meaning origin is going to be a foreign key. 646 00:31:12,033 --> 00:31:14,220 It's going to point to some other airport. 647 00:31:14,220 --> 00:31:20,410 And I'm going to add a special on delete property called models.cascade. 648 00:31:20,410 --> 00:31:22,530 And so, what Django models allow me to do 649 00:31:22,530 --> 00:31:27,130 is determine what happens when I delete an airport, for instance. 650 00:31:27,130 --> 00:31:30,810 Because if I have airport JFK International Airport, 651 00:31:30,810 --> 00:31:34,380 and I have flights that have an origin of JFK International Airport, what 652 00:31:34,380 --> 00:31:38,190 should happen to my data if I were to ever delete the airport at JFK? 653 00:31:38,190 --> 00:31:41,170 What should happen to any of the flights that have an origin of JFK? 654 00:31:41,170 --> 00:31:42,330 You know, there might be multiple options. 655 00:31:42,330 --> 00:31:44,536 And depending upon how your application is designed, 656 00:31:44,536 --> 00:31:46,410 you might want things to operate differently. 657 00:31:46,410 --> 00:31:48,285 Maybe you want there to be some sort of error 658 00:31:48,285 --> 00:31:50,820 where we say, don't allow you to delete the JFK airport 659 00:31:50,820 --> 00:31:53,880 if there are flights that have an origin of JFK. 660 00:31:53,880 --> 00:31:57,270 Or maybe you want the behavior to be, when I delete the JFK airport, 661 00:31:57,270 --> 00:32:00,750 go ahead and just delete all of the flights that have an origin of JFK 662 00:32:00,750 --> 00:32:02,880 because those flights can no longer exist. 663 00:32:02,880 --> 00:32:04,990 And there are other options as well. 664 00:32:04,990 --> 00:32:07,140 But what models.cascade is going to say is 665 00:32:07,140 --> 00:32:10,122 that if I delete the airport that has that particular origin, 666 00:32:10,122 --> 00:32:13,080 then delete the corresponding flights as well because those flights are 667 00:32:13,080 --> 00:32:13,970 no longer valid. 668 00:32:13,970 --> 00:32:15,480 And so these are just decisions that you'll 669 00:32:15,480 --> 00:32:18,060 have to make based on the desires of your particular application 670 00:32:18,060 --> 00:32:19,230 and what you need for that. 671 00:32:19,230 --> 00:32:21,810 And I'm using models.cascade in this case. 672 00:32:21,810 --> 00:32:24,900 And I'm also going to use a related name argument. 673 00:32:24,900 --> 00:32:27,739 And I'm going to call it departures. 674 00:32:27,739 --> 00:32:30,780 And what related name is going to allow me to do, which you'll see later, 675 00:32:30,780 --> 00:32:33,780 is that if I have an airport and I want to access 676 00:32:33,780 --> 00:32:37,050 all of the flights whose origin is that airport, 677 00:32:37,050 --> 00:32:40,130 I can use the name departures to be able to access that. 678 00:32:40,130 --> 00:32:43,410 And we'll see an example of that later probably. 679 00:32:43,410 --> 00:32:45,360 And likewise for destination, that's also 680 00:32:45,360 --> 00:32:48,260 going to be a foreign key that points to another airport, 681 00:32:48,260 --> 00:32:51,090 also have it cascade upon deletion. 682 00:32:51,090 --> 00:32:54,174 And it's related name is going to be arrivals instead. 683 00:32:54,174 --> 00:32:56,340 Because if I have an airport and I get its arrivals, 684 00:32:56,340 --> 00:33:00,060 that should get me all of the flights whose destination is that airport. 685 00:33:00,060 --> 00:33:04,110 Now notice here that I am not saying origin ID or destination ID. 686 00:33:04,110 --> 00:33:07,500 I'm just saying the origin is an airport and the destination is an airport. 687 00:33:07,500 --> 00:33:11,760 And I'm leaving it up to Django to worry about how actually to name the columns 688 00:33:11,760 --> 00:33:15,750 and how to do the associations of having an ID map to something else. 689 00:33:15,750 --> 00:33:19,410 All I have to worry about here is the data that I want to deal with, 690 00:33:19,410 --> 00:33:23,430 that the origin should be an airport and the destination should be an airport. 691 00:33:23,430 --> 00:33:27,870 And it's up to Django to figure out how to make sure those relationships work. 692 00:33:27,870 --> 00:33:29,681 So now, I've made those changes. 693 00:33:29,681 --> 00:33:32,430 And if I want to apply them to the database, what do I need to do? 694 00:33:32,430 --> 00:33:35,509 695 00:33:35,509 --> 00:33:36,050 Migrate them. 696 00:33:36,050 --> 00:33:36,550 Great. 697 00:33:36,550 --> 00:33:39,690 So I'm going to run python manage.py makemigrations. 698 00:33:39,690 --> 00:33:43,942 That's going to detect any changes that I've made to my models. 699 00:33:43,942 --> 00:33:45,650 And in this case, it's detected that I've 700 00:33:45,650 --> 00:33:47,330 created a new model called airport. 701 00:33:47,330 --> 00:33:52,550 And I've altered the destination and the origin fields on my existing flight. 702 00:33:52,550 --> 00:33:55,700 And now if I go python manage.py migrate, 703 00:33:55,700 --> 00:33:57,380 it's going to apply that migration. 704 00:33:57,380 --> 00:34:02,010 And now my database is updated with this new format that I've just created. 705 00:34:02,010 --> 00:34:05,390 And so, let's go ahead and go into the shell 706 00:34:05,390 --> 00:34:07,290 and experiment with that a little bit. 707 00:34:07,290 --> 00:34:12,770 So let's go from Flights.models, let's import Airport and Flight. 708 00:34:12,770 --> 00:34:15,199 Let me define a new airport called JFK which 709 00:34:15,199 --> 00:34:20,510 is going to be an airport whose code is JFK and whose city is New York City. 710 00:34:20,510 --> 00:34:26,030 And let me define a new airport called LHR whose code is LHR 711 00:34:26,030 --> 00:34:29,000 and whose city is London, for instance. 712 00:34:29,000 --> 00:34:32,389 And now if I want to create a new flight, all I need to say 713 00:34:32,389 --> 00:34:36,560 is f is going to be a flight whose origin is-- or actually, 714 00:34:36,560 --> 00:34:40,709 let me first save JFK and save LHR because I've just created those. 715 00:34:40,709 --> 00:34:42,500 But if I want to create a new flight, I can 716 00:34:42,500 --> 00:34:47,659 say I want a new flight whose origin is JFK, whose destination is LHR, 717 00:34:47,659 --> 00:34:49,790 and whose duration is 415 minutes. 718 00:34:49,790 --> 00:34:52,460 The origin is, in fact, JFK Airport. 719 00:34:52,460 --> 00:34:54,889 The destination is London Heathrow Airport. 720 00:34:54,889 --> 00:34:58,402 I don't need to specifically specify use the ID column. 721 00:34:58,402 --> 00:35:00,110 Django is trying to abstract some of this 722 00:35:00,110 --> 00:35:02,870 away so that I don't need to worry about it as much. 723 00:35:02,870 --> 00:35:04,550 So I create that new flight. 724 00:35:04,550 --> 00:35:06,440 I'm going to go ahead and save that flight. 725 00:35:06,440 --> 00:35:11,280 And now I have two airports and a flight saved in my database. 726 00:35:11,280 --> 00:35:16,760 And so if I go to f.origin, I notice that f.origin is this airport object. 727 00:35:16,760 --> 00:35:21,150 Now I can just say f.origin.code, for instance, 728 00:35:21,150 --> 00:35:24,590 to get JFK as the code of the origin of this flight, 729 00:35:24,590 --> 00:35:27,890 or f.origin.city to get New York City. 730 00:35:27,890 --> 00:35:36,485 And likewise, if I have JFK, and I go to jfk.departures.all 731 00:35:36,485 --> 00:35:40,070 what that's going to do is query for all of the departures that 732 00:35:40,070 --> 00:35:41,510 are departing from JFK. 733 00:35:41,510 --> 00:35:44,660 It's going to give me this query setback that has flight 734 00:35:44,660 --> 00:35:47,630 from New York City to London. 735 00:35:47,630 --> 00:35:52,040 So questions about the models that we created or the migration that we made 736 00:35:52,040 --> 00:35:54,486 or how our data is now going to operate? 737 00:35:54,486 --> 00:35:59,200 738 00:35:59,200 --> 00:36:01,690 Let's move on to talking about rendering templates. 739 00:36:01,690 --> 00:36:04,150 And so one feature that we talked about just a moment ago 740 00:36:04,150 --> 00:36:06,040 was that we might want for our application 741 00:36:06,040 --> 00:36:10,300 to be able to not just return text but to actually return an HTML 742 00:36:10,300 --> 00:36:12,370 template, much like we saw in Flask. 743 00:36:12,370 --> 00:36:16,932 And so just like in Flask where we used an HTML file 744 00:36:16,932 --> 00:36:18,640 to say, render this template, we're going 745 00:36:18,640 --> 00:36:23,140 to do something very similar in this application as well. 746 00:36:23,140 --> 00:36:28,075 Rather than return HTTP response flight, I'm going to return render. 747 00:36:28,075 --> 00:36:29,700 And render takes a couple of arguments. 748 00:36:29,700 --> 00:36:31,480 The first argument is the request. 749 00:36:31,480 --> 00:36:35,440 And the second argument is the name of the HTML template 750 00:36:35,440 --> 00:36:36,680 that we want to render. 751 00:36:36,680 --> 00:36:40,810 And so let's go ahead and render flights/index.html as the template I 752 00:36:40,810 --> 00:36:41,890 want to render. 753 00:36:41,890 --> 00:36:45,612 Of course, now I need a flight/index.html file. 754 00:36:45,612 --> 00:36:48,820 And by default, those are going to be stored in a directory called templates. 755 00:36:48,820 --> 00:36:52,090 So I'll create a new folder, called it Templates. 756 00:36:52,090 --> 00:36:55,300 Inside of Templates, I'll create a new folder called Flights. 757 00:36:55,300 --> 00:37:00,531 And inside of Flights, I'll go out and create a new file called index.html. 758 00:37:00,531 --> 00:37:04,550 And that's just going to be a basic HTML file that 759 00:37:04,550 --> 00:37:11,510 is going to be the template that I want rendered when I run my application. 760 00:37:11,510 --> 00:37:14,810 So right now, it's just going to say flights. 761 00:37:14,810 --> 00:37:21,830 And now if I exit and run the server, when I go to this URL, 762 00:37:21,830 --> 00:37:26,360 I now see HTML page that has a big heading called Flights and a title 763 00:37:26,360 --> 00:37:28,311 up here that says Flights. 764 00:37:28,311 --> 00:37:30,560 And so this is very analogous to what we had in Flask. 765 00:37:30,560 --> 00:37:34,340 We're rendering this particular HTML file. 766 00:37:34,340 --> 00:37:36,729 And here's the contents of the HTML file. 767 00:37:36,729 --> 00:37:39,020 But now, of course, we don't just want our Flights page 768 00:37:39,020 --> 00:37:40,790 to say Flights in this big heading. 769 00:37:40,790 --> 00:37:43,490 We want it to actually show us the flights that 770 00:37:43,490 --> 00:37:45,210 exist inside of our database. 771 00:37:45,210 --> 00:37:49,700 So in Flask, how would we have done something like that? 772 00:37:49,700 --> 00:37:50,630 AUDIENCE: [INAUDIBLE] 773 00:37:50,630 --> 00:37:50,810 SPEAKER 1: Yeah. 774 00:37:50,810 --> 00:37:51,350 With Jinja. 775 00:37:51,350 --> 00:37:53,990 We would pass information into this template 776 00:37:53,990 --> 00:37:55,310 in order to allow it to render. 777 00:37:55,310 --> 00:37:59,420 And Django has its own templating system that looks very, very similar to Jinja. 778 00:37:59,420 --> 00:38:02,180 And in fact, in many ways, it looks identical. 779 00:38:02,180 --> 00:38:03,680 And we'll go ahead and use that now. 780 00:38:03,680 --> 00:38:08,870 And so the way Django passes information into the template 781 00:38:08,870 --> 00:38:11,177 is through a special context dictionary. 782 00:38:11,177 --> 00:38:13,010 And so this context dictionary is just going 783 00:38:13,010 --> 00:38:15,740 to be a Python dictionary that will maintain keys and values. 784 00:38:15,740 --> 00:38:18,770 Keys as the things we want to plug in to the template, 785 00:38:18,770 --> 00:38:20,120 as the names of those things. 786 00:38:20,120 --> 00:38:22,710 And the values are what we actually want to plug in. 787 00:38:22,710 --> 00:38:26,150 So let's say Flights is going to be something we want our template 788 00:38:26,150 --> 00:38:27,870 to know something about. 789 00:38:27,870 --> 00:38:31,280 And it should have a value of flight.objects.all. 790 00:38:31,280 --> 00:38:33,200 I just want a query for all the flights. 791 00:38:33,200 --> 00:38:35,000 Save that inside of Flights. 792 00:38:35,000 --> 00:38:38,240 And we're going to ultimately pass that context 793 00:38:38,240 --> 00:38:43,000 in to our template as a third argument to it. 794 00:38:43,000 --> 00:38:44,920 Of course, now I'm using this variable flight 795 00:38:44,920 --> 00:38:46,384 which doesn't exist in this file. 796 00:38:46,384 --> 00:38:47,800 So I'm going to need to import it. 797 00:38:47,800 --> 00:38:51,610 I'll say, from .models import Flight. 798 00:38:51,610 --> 00:38:55,470 In other words, from this current packages models package, 799 00:38:55,470 --> 00:38:59,260 our models module, import the flight variable. 800 00:38:59,260 --> 00:39:03,960 And so now I can query for all of the flights, save it inside of the context, 801 00:39:03,960 --> 00:39:07,960 past the context in to my template. 802 00:39:07,960 --> 00:39:11,020 And now in my template, I can create an unordered list. 803 00:39:11,020 --> 00:39:14,080 And this syntax is going to look basically identical to Jinja 804 00:39:14,080 --> 00:39:15,370 which we saw from Flask. 805 00:39:15,370 --> 00:39:19,630 I can say, for flight in flights, create a for loop that's 806 00:39:19,630 --> 00:39:21,850 going to loop over all of my flights. 807 00:39:21,850 --> 00:39:26,190 And for each one of those, let's have a list item where that list item is going 808 00:39:26,190 --> 00:39:29,370 to be just plugging in .flight. 809 00:39:29,370 --> 00:39:32,090 810 00:39:32,090 --> 00:39:34,870 And so now, if I refresh the page, what I get 811 00:39:34,870 --> 00:39:38,020 is Flights with this unordered list of the single flight that I have. 812 00:39:38,020 --> 00:39:42,400 And notice that I didn't specifically say, use the ID of the flight 813 00:39:42,400 --> 00:39:44,120 and the origin and the destination. 814 00:39:44,120 --> 00:39:46,840 I just said, in curly braces, plug in the flight here. 815 00:39:46,840 --> 00:39:50,031 So why is it rendering nicely with the ID and the origin 816 00:39:50,031 --> 00:39:52,030 and the destination with the word to in between? 817 00:39:52,030 --> 00:39:53,305 AUDIENCE: [INAUDIBLE] string. 818 00:39:53,305 --> 00:39:53,940 SPEAKER 1: Yes. 819 00:39:53,940 --> 00:39:55,981 Exactly, from the string function, the underscore 820 00:39:55,981 --> 00:39:59,130 underscore STR function that defines what should the object look 821 00:39:59,130 --> 00:40:01,770 like when you just paste it into the terminal 822 00:40:01,770 --> 00:40:04,290 or when you just render it on an HTML page. 823 00:40:04,290 --> 00:40:07,830 It will use that STR function to determine how that flight actually 824 00:40:07,830 --> 00:40:09,686 shows up on the page. 825 00:40:09,686 --> 00:40:12,060 So now we've recreated a lot of that Flask functionality, 826 00:40:12,060 --> 00:40:15,960 of taking context information, passing it into a template and then using it. 827 00:40:15,960 --> 00:40:19,564 Questions about anything so far? 828 00:40:19,564 --> 00:40:20,064 Yeah? 829 00:40:20,064 --> 00:40:24,954 AUDIENCE: Why is the [INAUDIBLE]? 830 00:40:24,954 --> 00:40:26,600 SPEAKER 1: Oh, good question. 831 00:40:26,600 --> 00:40:30,610 So the question was, why is this directory structure inside of templates 832 00:40:30,610 --> 00:40:32,860 a separate directory called Flights inside 833 00:40:32,860 --> 00:40:37,210 of which is index.html as opposed to just having index.html there. 834 00:40:37,210 --> 00:40:40,700 You could do it where you just had index.html inside of Flights. 835 00:40:40,700 --> 00:40:44,910 And you change the template name and views.py to just be flights.html. 836 00:40:44,910 --> 00:40:48,520 It's generally good practice to what's called namespace templates 837 00:40:48,520 --> 00:40:51,580 by putting them in a directory with the name corresponding to the app. 838 00:40:51,580 --> 00:40:53,860 Because if in larger Django projects, you 839 00:40:53,860 --> 00:40:57,970 had multiple different apps, each of which had an index.html file, 840 00:40:57,970 --> 00:41:01,990 that would potentially create ambiguity, where if you tried to render index.html 841 00:41:01,990 --> 00:41:04,120 Django wouldn't know, do you mean index.html 842 00:41:04,120 --> 00:41:06,890 from app number one over here or app number two over there. 843 00:41:06,890 --> 00:41:10,180 And so what namespacing the templates does is it means that I can explicitly 844 00:41:10,180 --> 00:41:15,640 say, flight/index.html is the index.html template of the Flights app. 845 00:41:15,640 --> 00:41:18,640 And that way, even if there are other apps that have an index.html, 846 00:41:18,640 --> 00:41:21,111 there's no ambiguity as to which one I actually mean. 847 00:41:21,111 --> 00:41:24,338 AUDIENCE: So this template's folder is already specific to the Flights app? 848 00:41:24,338 --> 00:41:25,130 SPEAKER 1: Correct. 849 00:41:25,130 --> 00:41:27,770 So this template's folder is specific to the Fights app. 850 00:41:27,770 --> 00:41:30,260 But when Django is rendering a response, it's 851 00:41:30,260 --> 00:41:32,240 not looking only in this templates folder. 852 00:41:32,240 --> 00:41:34,820 It could look in templates all across the entire project. 853 00:41:34,820 --> 00:41:38,309 So that ambiguity is still possible. 854 00:41:38,309 --> 00:41:41,350 Good question, and certainly something that's not very intuitive at first 855 00:41:41,350 --> 00:41:43,260 and it seems sort of redundant. 856 00:41:43,260 --> 00:41:45,630 Other questions about the structure of things so far? 857 00:41:45,630 --> 00:41:49,710 858 00:41:49,710 --> 00:41:51,990 So what we'll take a look at now is what we 859 00:41:51,990 --> 00:41:56,850 need to happen if we wanted to allow ourselves to add or edit 860 00:41:56,850 --> 00:41:58,342 data inside of our database. 861 00:41:58,342 --> 00:42:01,050 And so right now, we've been doing this all via the command line, 862 00:42:01,050 --> 00:42:02,550 that I logged into the shell. 863 00:42:02,550 --> 00:42:05,852 I then use that shell to create new flights, create new airports. 864 00:42:05,852 --> 00:42:08,310 What I'd really like to do is not have to write Python code 865 00:42:08,310 --> 00:42:11,018 to be able to do that, but to be able to go to part of my website 866 00:42:11,018 --> 00:42:15,150 where I can click add a new flight from this location to that location 867 00:42:15,150 --> 00:42:18,107 and be able to save that information or update existing flights. 868 00:42:18,107 --> 00:42:20,940 And if you were doing this in Flask, it would be a non-trivial task. 869 00:42:20,940 --> 00:42:23,340 You'd have to build out a page to list all the flights, 870 00:42:23,340 --> 00:42:25,431 build out a page to list all of the airports, 871 00:42:25,431 --> 00:42:27,930 figure out a way to make sure that when you add a new flight 872 00:42:27,930 --> 00:42:30,480 you can choose from one of the valid airports. 873 00:42:30,480 --> 00:42:32,950 And this would be quite a fair bit of code. 874 00:42:32,950 --> 00:42:36,630 But what Django does, because it's designed for applications 875 00:42:36,630 --> 00:42:38,462 that use a lot of different types of data 876 00:42:38,462 --> 00:42:40,170 and they know-- the designers of Django-- 877 00:42:40,170 --> 00:42:43,350 knew it would be quite tedious if anytime you 878 00:42:43,350 --> 00:42:46,260 wanted to have an application that let us add or modify information, 879 00:42:46,260 --> 00:42:49,200 you had to build that yourself, Django comes with a built in app 880 00:42:49,200 --> 00:42:54,237 called Admin which makes it very easy to add and modify existing data. 881 00:42:54,237 --> 00:42:57,070 And so I'll show you what that admin interface looks like right now. 882 00:42:57,070 --> 00:42:59,940 And this is perhaps one of the most powerful features of Django, 883 00:42:59,940 --> 00:43:03,190 especially when it comes to dealing and manipulating with data. 884 00:43:03,190 --> 00:43:08,070 So I'm going to go into admin.py now, this file inside of my Flights app. 885 00:43:08,070 --> 00:43:14,250 And the first thing I'm going to do is say from .models import Airport 886 00:43:14,250 --> 00:43:17,970 and Flight because I want my admin interface to know something about 887 00:43:17,970 --> 00:43:19,320 the airport and flight. 888 00:43:19,320 --> 00:43:23,520 And what I'm going to do is say, admin.site.register.airport 889 00:43:23,520 --> 00:43:26,445 and admin.site.register.flight. 890 00:43:26,445 --> 00:43:29,640 So the Admin app is an app that's built into Django 891 00:43:29,640 --> 00:43:32,370 that makes it very easy to update existing models, 892 00:43:32,370 --> 00:43:34,170 to modify the data inside of models. 893 00:43:34,170 --> 00:43:38,110 And what I'm doing here is registering these models with my admin site, 894 00:43:38,110 --> 00:43:41,580 saying that I want my admin site to be able to manipulate 895 00:43:41,580 --> 00:43:44,800 Airports and Flights. 896 00:43:44,800 --> 00:43:46,810 In order to access the Admin site, you're 897 00:43:46,810 --> 00:43:48,870 going to need to log into the Admin site. 898 00:43:48,870 --> 00:43:52,120 And see, here's another case where in a Flask application, if you wanted a way 899 00:43:52,120 --> 00:43:54,828 to log into something, you'd have to build this out for yourself, 900 00:43:54,828 --> 00:44:00,160 design a users table, figure out how to let people be authenticated. 901 00:44:00,160 --> 00:44:04,820 But in Django, this is all built for you out of the box. 902 00:44:04,820 --> 00:44:09,160 And so what I'm going to do now is just create a first user account 903 00:44:09,160 --> 00:44:10,880 inside of my web application. 904 00:44:10,880 --> 00:44:15,220 And there's a special command for that, python manage.py createsuperuser which 905 00:44:15,220 --> 00:44:17,890 is going to create a super user account, an account that 906 00:44:17,890 --> 00:44:21,730 has access to everything in my database, so to speak. 907 00:44:21,730 --> 00:44:23,080 And so I'm going to create that. 908 00:44:23,080 --> 00:44:24,496 It asks me to type in a user name. 909 00:44:24,496 --> 00:44:25,960 I'll do brian. 910 00:44:25,960 --> 00:44:28,710 Email address, I'll type in email address. 911 00:44:28,710 --> 00:44:31,400 Password is just the password I want to use. 912 00:44:31,400 --> 00:44:32,650 I'll type in a password. 913 00:44:32,650 --> 00:44:33,590 Type it in twice. 914 00:44:33,590 --> 00:44:35,320 And now it's created that user for me. 915 00:44:35,320 --> 00:44:38,440 And so that's been saved into a users table that I didn't have to create. 916 00:44:38,440 --> 00:44:41,980 It was built into Django, built into this project 917 00:44:41,980 --> 00:44:43,850 without me needing to do anything. 918 00:44:43,850 --> 00:44:46,510 So now let's take a look at the Admin site itself. 919 00:44:46,510 --> 00:44:51,760 So if you were paying very careful attention to the urls.py file 920 00:44:51,760 --> 00:44:55,000 inside of the project, you'll notice that what we did 921 00:44:55,000 --> 00:45:00,400 is we first created a path that just took us to our application's URLs. 922 00:45:00,400 --> 00:45:02,440 But there was also this admin route that was 923 00:45:02,440 --> 00:45:06,070 built in to the URL patterns for us, that came with the application, 924 00:45:06,070 --> 00:45:07,290 that I didn't put there. 925 00:45:07,290 --> 00:45:11,100 And so let's go there now and see what it is. 926 00:45:11,100 --> 00:45:14,900 So I'm going to say python manage.py run server. 927 00:45:14,900 --> 00:45:18,050 I'll go ahead and go to this URL. 928 00:45:18,050 --> 00:45:21,524 And I'm going to go to /admin, because that was the URL that was given to me. 929 00:45:21,524 --> 00:45:24,440 And when I go there, I'm taken to this login page that I didn't write. 930 00:45:24,440 --> 00:45:27,200 It's an app built into Django called Django's Admin App. 931 00:45:27,200 --> 00:45:30,780 I'll type in that username that I just created, that password. 932 00:45:30,780 --> 00:45:33,470 And what I'm taken to now is a user interface 933 00:45:33,470 --> 00:45:38,300 that lets me add and manipulate the data inside of my database, 934 00:45:38,300 --> 00:45:40,470 that I can click on airports for instance, 935 00:45:40,470 --> 00:45:43,110 and see here my two airports, London and New York. 936 00:45:43,110 --> 00:45:46,190 I can click on London if I want to change the code for London airport, 937 00:45:46,190 --> 00:45:49,370 I can change that here, change the city. 938 00:45:49,370 --> 00:45:53,430 But let's just say now that I want to create a new airport, for instance. 939 00:45:53,430 --> 00:45:55,100 So let's say I add a new airport. 940 00:45:55,100 --> 00:45:59,680 I want the code to be PVG and the city to be Shanghai. 941 00:45:59,680 --> 00:46:00,880 And I save that. 942 00:46:00,880 --> 00:46:03,482 And now I've created a new airport inside my database. 943 00:46:03,482 --> 00:46:05,940 And this is all stuff I'd have to build for myself in Flask 944 00:46:05,940 --> 00:46:08,780 but you don't need to in Django because it all comes for you 945 00:46:08,780 --> 00:46:10,310 inside of Django's admin interface. 946 00:46:10,310 --> 00:46:11,720 You just click Add Airport. 947 00:46:11,720 --> 00:46:15,270 You type in the city and code that you want. 948 00:46:15,270 --> 00:46:16,160 You save it. 949 00:46:16,160 --> 00:46:18,440 And then that airport is added. 950 00:46:18,440 --> 00:46:21,320 Likewise, I can do the same thing with individual flights. 951 00:46:21,320 --> 00:46:22,295 I can click on Flights. 952 00:46:22,295 --> 00:46:24,920 I see that I have this existing flight from New York to London. 953 00:46:24,920 --> 00:46:27,980 If I want to create a new flight, I just click Add Flight here. 954 00:46:27,980 --> 00:46:29,780 And the whole process of the origin needs 955 00:46:29,780 --> 00:46:32,300 to be an airport is auto populated for me. 956 00:46:32,300 --> 00:46:35,840 I can just select, OK, this is a flight from Shanghai to Paris. 957 00:46:35,840 --> 00:46:38,900 And the duration of that flight is going to be 760 minutes. 958 00:46:38,900 --> 00:46:41,510 And I can save that and now I've created a second flight 959 00:46:41,510 --> 00:46:43,630 inside of my admin interface as well. 960 00:46:43,630 --> 00:46:45,890 And so this just makes it very easy for me 961 00:46:45,890 --> 00:46:48,950 to manipulate data using a web user interface that's 962 00:46:48,950 --> 00:46:51,950 created for me, without me needing to go through the effort of writing 963 00:46:51,950 --> 00:46:53,780 that for myself. 964 00:46:53,780 --> 00:46:57,580 Questions about this interface? 965 00:46:57,580 --> 00:47:00,310 So this comes out of the box with all Django applications. 966 00:47:00,310 --> 00:47:03,640 And all you need to do to be able to use it was for Airports and Flights 967 00:47:03,640 --> 00:47:04,540 to show up here. 968 00:47:04,540 --> 00:47:07,390 I just needed to register these models with the admin 969 00:47:07,390 --> 00:47:11,930 site on that admin.py file just a moment ago. 970 00:47:11,930 --> 00:47:12,630 So yes? 971 00:47:12,630 --> 00:47:13,130 Question? 972 00:47:13,130 --> 00:47:15,425 AUDIENCE: So this is on the project level? 973 00:47:15,425 --> 00:47:17,720 Or do you have it on that [? app ?] [? level? ?] 974 00:47:17,720 --> 00:47:20,390 SPEAKER 1: So the Admin interface you're looking at here, 975 00:47:20,390 --> 00:47:22,490 this is part of an Admin app. 976 00:47:22,490 --> 00:47:24,505 So it is an app within my project. 977 00:47:24,505 --> 00:47:25,880 But it's not an app that I wrote. 978 00:47:25,880 --> 00:47:27,797 It's an app written, that's built into Django. 979 00:47:27,797 --> 00:47:28,296 Yeah. 980 00:47:28,296 --> 00:47:30,250 AUDIENCE: But it's not an each individual-- 981 00:47:30,250 --> 00:47:34,262 Flights1 and I could have another app that did something else [INAUDIBLE]?? 982 00:47:34,262 --> 00:47:35,470 SPEAKER 1: Oh, good question. 983 00:47:35,470 --> 00:47:37,350 So what would happen if I had multiple different apps 984 00:47:37,350 --> 00:47:38,820 with multiple different models? 985 00:47:38,820 --> 00:47:40,500 Where would these show up? 986 00:47:40,500 --> 00:47:42,300 They would all show up on this Admin site. 987 00:47:42,300 --> 00:47:44,790 What you'll notice here is that this Flights heading, 988 00:47:44,790 --> 00:47:47,790 that corresponds with the name of the app, that these models Airports 989 00:47:47,790 --> 00:47:50,920 and Flights, these are models inside of my Flights app. 990 00:47:50,920 --> 00:47:53,770 And likewise, I have this authentication and authorization app-- 991 00:47:53,770 --> 00:47:56,310 which I didn't create, it's just built into Django-- 992 00:47:56,310 --> 00:47:58,355 that has users already and groups of users 993 00:47:58,355 --> 00:48:00,480 if you want a group users into different permission 994 00:48:00,480 --> 00:48:03,780 levels, which is a common thing that you might want to do in a web application. 995 00:48:03,780 --> 00:48:06,060 That's built into the authentication authorization 996 00:48:06,060 --> 00:48:07,790 app that comes with Django. 997 00:48:07,790 --> 00:48:09,540 And so those models are already registered 998 00:48:09,540 --> 00:48:11,370 without me needing to do anything. 999 00:48:11,370 --> 00:48:13,292 And so if I added yet another app and had 1000 00:48:13,292 --> 00:48:15,000 models that I wanted to interact with, it 1001 00:48:15,000 --> 00:48:17,041 would show up as a separate heading underneath it 1002 00:48:17,041 --> 00:48:19,089 with additional models below that. 1003 00:48:19,089 --> 00:48:21,584 AUDIENCE: Is there ever any error checking of what you do? 1004 00:48:21,584 --> 00:48:26,075 Like if I could enter a flight that went from Paris to Paris, which I could, 1005 00:48:26,075 --> 00:48:29,568 is there a way to stop me from doing this [INAUDIBLE]?? 1006 00:48:29,568 --> 00:48:30,760 SPEAKER 1: Great question. 1007 00:48:30,760 --> 00:48:33,010 Is there a way to stop us from doing something 1008 00:48:33,010 --> 00:48:36,264 stupid like adding a flight from Paris to Paris, which right now we could do? 1009 00:48:36,264 --> 00:48:37,180 And the answer is yes. 1010 00:48:37,180 --> 00:48:39,770 So this is Django's default Admin interface. 1011 00:48:39,770 --> 00:48:42,460 But Django lets you customize this Admin interface 1012 00:48:42,460 --> 00:48:46,229 in almost any way you want adding your own logic and your own code to it. 1013 00:48:46,229 --> 00:48:48,770 It's a little bit beyond what will have time to go into here. 1014 00:48:48,770 --> 00:48:50,728 But certainly it's something that you could do. 1015 00:48:50,728 --> 00:48:53,847 You could modify this Admin interface to add constraints, 1016 00:48:53,847 --> 00:48:55,930 make it behave the way that you want it to behave. 1017 00:48:55,930 --> 00:48:59,820 And certainly that's a possibility. 1018 00:48:59,820 --> 00:49:01,770 So this is often just a great place to jump 1019 00:49:01,770 --> 00:49:05,400 start the process of allowing yourself to modify data. 1020 00:49:05,400 --> 00:49:09,120 And this Admin interface isn't meant to be used by all users of your website. 1021 00:49:09,120 --> 00:49:11,416 It's generally meant for content managers 1022 00:49:11,416 --> 00:49:13,290 of your website, the people that are managing 1023 00:49:13,290 --> 00:49:16,260 the information that other people are seeing, where you will likely 1024 00:49:16,260 --> 00:49:20,310 use the Admin interface to populate your models, add the data that you want. 1025 00:49:20,310 --> 00:49:23,490 And the users will be looking at a page sort 1026 00:49:23,490 --> 00:49:26,340 of like this that is rendering information 1027 00:49:26,340 --> 00:49:31,690 that comes from the data that's been populated into your site already. 1028 00:49:31,690 --> 00:49:35,200 Let's take a look at adding some more routes to this application. 1029 00:49:35,200 --> 00:49:38,680 Maybe I now want the ability to have arguments in my URLs, 1030 00:49:38,680 --> 00:49:42,259 like an integer saying if I go to myurl/1, that should take me 1031 00:49:42,259 --> 00:49:43,800 to information about flight number 1. 1032 00:49:43,800 --> 00:49:47,540 And likewise /2 should take me information about flight number 2. 1033 00:49:47,540 --> 00:49:49,290 So to do that, I'll need to add a new URL. 1034 00:49:49,290 --> 00:49:52,930 I'll go into my urls.py file. 1035 00:49:52,930 --> 00:49:56,980 And I'm going to say whenever someone goes to a particular URL-- 1036 00:49:56,980 --> 00:49:58,630 and I could just type a URL are here-- 1037 00:49:58,630 --> 00:50:02,050 but I want someone to be able to type in any number, any integer. 1038 00:50:02,050 --> 00:50:05,950 And so the syntax for this looks a lot like Flask. 1039 00:50:05,950 --> 00:50:08,800 If they type an integer, we'll call it flight id, 1040 00:50:08,800 --> 00:50:13,960 then the function I want to run is views.flight. 1041 00:50:13,960 --> 00:50:15,830 Of course, view.flight doesn't exist yet. 1042 00:50:15,830 --> 00:50:17,590 So let me go ahead and create it. 1043 00:50:17,590 --> 00:50:24,060 I go into views.py, add a flight function. 1044 00:50:24,060 --> 00:50:31,480 And inside of the flight function, I'm going to say let's try and say flight 1045 00:50:31,480 --> 00:50:37,690 equals flight.objects.get pk equals-- 1046 00:50:37,690 --> 00:50:39,910 and then I would need the flight id. 1047 00:50:39,910 --> 00:50:41,802 So actually, sorry, the flight id is going 1048 00:50:41,802 --> 00:50:44,260 to be provided as a second argument to the flight function. 1049 00:50:44,260 --> 00:50:46,300 Because it was a parameter in the URL, it 1050 00:50:46,300 --> 00:50:49,190 gets passed into the function when it gets called. 1051 00:50:49,190 --> 00:50:53,170 And so the flight, I'm going to get the flight with PL, Primary Key, flight id. 1052 00:50:53,170 --> 00:50:54,910 I could also say, id equals flight id. 1053 00:50:54,910 --> 00:50:56,160 They're almost the same thing. 1054 00:50:56,160 --> 00:50:59,260 There's some slight, subtle differences because your primary key might not 1055 00:50:59,260 --> 00:51:02,530 be called id for instance or you might have a more complicated primary key. 1056 00:51:02,530 --> 00:51:06,430 But here I'm saying, get the flight number whose number is flight id. 1057 00:51:06,430 --> 00:51:07,930 And what could go wrong here? 1058 00:51:07,930 --> 00:51:13,051 Well, if the flight doesn't exist, if I tried to access flight number four 1059 00:51:13,051 --> 00:51:16,300 but I don't have a flight number four, for instance, or flight number 28, then 1060 00:51:16,300 --> 00:51:17,674 it's going to throw an exception. 1061 00:51:17,674 --> 00:51:22,700 So I'm going to say, except Flight.doesnotexist. 1062 00:51:22,700 --> 00:51:25,310 This is a special exception built into all of my Django models 1063 00:51:25,310 --> 00:51:29,540 that is thrown whenever I try and access a flight that doesn't exist. 1064 00:51:29,540 --> 00:51:32,080 So if the flight doesn't exist, then what I want to do 1065 00:51:32,080 --> 00:51:33,472 is raise some sort of error. 1066 00:51:33,472 --> 00:51:34,930 There should be some sort of error. 1067 00:51:34,930 --> 00:51:40,380 And Django comes in with a built in http 404 for 404 not found error. 1068 00:51:40,380 --> 00:51:45,830 Or I can just say, flight does not exist here. 1069 00:51:45,830 --> 00:51:48,270 And if the flight does exist, then let me just go ahead 1070 00:51:48,270 --> 00:51:50,670 and put it inside of a context object. 1071 00:51:50,670 --> 00:51:52,320 The flight is going to be the flight. 1072 00:51:52,320 --> 00:51:54,870 And I'm going to render a response. 1073 00:51:54,870 --> 00:51:57,780 I'm going to render the flight.html page, which I haven't created yet 1074 00:51:57,780 --> 00:52:02,380 but I will in a moment, passing in that context. 1075 00:52:02,380 --> 00:52:10,830 And so, what I'll do here is I need to import this http 404 function. 1076 00:52:10,830 --> 00:52:12,390 And I'll import it up top. 1077 00:52:12,390 --> 00:52:14,880 And so now I have this http 404 function. 1078 00:52:14,880 --> 00:52:18,310 And now what I need to do is actually create this flight.html file, 1079 00:52:18,310 --> 00:52:22,600 the file that is going to show me what's happening on any individual flight. 1080 00:52:22,600 --> 00:52:25,180 And so I'll go ahead and inside my Flights directory, 1081 00:52:25,180 --> 00:52:27,870 add a new file called flight.html. 1082 00:52:27,870 --> 00:52:30,720 It's going to look a lot like index.html so I'll just 1083 00:52:30,720 --> 00:52:32,139 go ahead and copy it for now. 1084 00:52:32,139 --> 00:52:34,680 But the fact that I'm copying this code should suggest to you 1085 00:52:34,680 --> 00:52:36,240 that there may be design improvements to be made 1086 00:52:36,240 --> 00:52:38,110 that we'll take a look at it a moment. 1087 00:52:38,110 --> 00:52:41,820 And this is going to be flight, flight id. 1088 00:52:41,820 --> 00:52:46,470 And let's go ahead and include some information about its-- 1089 00:52:46,470 --> 00:52:50,250 origin is going to be flight.origin. 1090 00:52:50,250 --> 00:52:53,460 And its destination is going to be flight.destination. 1091 00:52:53,460 --> 00:52:57,080 1092 00:52:57,080 --> 00:53:03,790 So now, if I go back here, this default route shows me all of my flights. 1093 00:53:03,790 --> 00:53:08,620 If I go to /1, now it shows me flight 1 whose origin is New York City, 1094 00:53:08,620 --> 00:53:10,630 whose destination is London. 1095 00:53:10,630 --> 00:53:14,230 And likewise if I go to flight/2, that shows me Shanghai to Paris. 1096 00:53:14,230 --> 00:53:17,770 If I go to /5, for instance, a flight that doesn't exist, 1097 00:53:17,770 --> 00:53:20,380 then I get page not found, the flight doesn't exist. 1098 00:53:20,380 --> 00:53:25,750 This is Django's default 404 error page when I have the debug settings to true. 1099 00:53:25,750 --> 00:53:30,130 You can customize the error pages, of course, if you'd like to as well. 1100 00:53:30,130 --> 00:53:33,330 But questions about anything we did so far? 1101 00:53:33,330 --> 00:53:37,990 So the three steps that we needed to do to make this happen were add the URL. 1102 00:53:37,990 --> 00:53:39,910 So when the user goes to this URL, what should 1103 00:53:39,910 --> 00:53:41,440 happen when they type in a number? 1104 00:53:41,440 --> 00:53:43,630 Send them to the views.flight function. 1105 00:53:43,630 --> 00:53:47,110 Then in the flight function, we said try to get the flight. 1106 00:53:47,110 --> 00:53:49,444 If it doesn't exist, raise a 404 error. 1107 00:53:49,444 --> 00:53:52,360 And then render this template passing in the context of the new flight 1108 00:53:52,360 --> 00:53:54,820 that we just wanted to display information about. 1109 00:53:54,820 --> 00:53:57,760 And inside of our html page, we were then able to, 1110 00:53:57,760 --> 00:54:01,030 in the body of the html, display information 1111 00:54:01,030 --> 00:54:03,574 about that particular flight. 1112 00:54:03,574 --> 00:54:04,740 Questions about any of that? 1113 00:54:04,740 --> 00:54:07,099 1114 00:54:07,099 --> 00:54:08,140 We'll take a short break. 1115 00:54:08,140 --> 00:54:10,510 And when we come back, we'll take a look at some additional features of Django 1116 00:54:10,510 --> 00:54:14,650 and some more powerful things you can do with its model and database structure. 1117 00:54:14,650 --> 00:54:15,700 Welcome back, everyone. 1118 00:54:15,700 --> 00:54:17,010 So let's pick up where we left off. 1119 00:54:17,010 --> 00:54:18,801 We were working on this airline application 1120 00:54:18,801 --> 00:54:20,740 and working on building a system for people 1121 00:54:20,740 --> 00:54:23,410 to look at-- an airline could use to see a list of flights 1122 00:54:23,410 --> 00:54:25,390 and look at individual flight pages. 1123 00:54:25,390 --> 00:54:30,550 And right now, our airline program has two main routes. 1124 00:54:30,550 --> 00:54:33,940 We have the default route which just displays a list of flights. 1125 00:54:33,940 --> 00:54:36,490 And then if we go to slash something, it displays 1126 00:54:36,490 --> 00:54:38,170 details for that particular flight. 1127 00:54:38,170 --> 00:54:42,010 What we might like now is the ability to link between these two 1128 00:54:42,010 --> 00:54:45,170 such that the individual flight page can link back to the original page 1129 00:54:45,170 --> 00:54:48,250 and the original page can link back to the individual flight page. 1130 00:54:48,250 --> 00:54:53,890 And a common paradigm for doing this in Django is to name our URLs. 1131 00:54:53,890 --> 00:54:56,910 So right now, each one of our URL paths has two things. 1132 00:54:56,910 --> 00:54:59,360 It has the route you would go to and the function 1133 00:54:59,360 --> 00:55:01,875 that would be called when you were to go to that route. 1134 00:55:01,875 --> 00:55:04,000 But what we're going to do now is add a third thing 1135 00:55:04,000 --> 00:55:06,100 to each of these paths, which is a name. 1136 00:55:06,100 --> 00:55:07,460 I going to call the-- 1137 00:55:07,460 --> 00:55:09,970 I'm going to name the default route just index. 1138 00:55:09,970 --> 00:55:12,784 And I'm going to name the individual flight route, flight. 1139 00:55:12,784 --> 00:55:14,575 And the reason I'm giving it a name is such 1140 00:55:14,575 --> 00:55:18,640 that when I link to a different route at some other page, 1141 00:55:18,640 --> 00:55:24,670 I would like to be able to refer to that route by name rather than by route. 1142 00:55:24,670 --> 00:55:28,900 I certainly could link to just, if you click here, you go to flash. /1 or /2. 1143 00:55:28,900 --> 00:55:32,500 But Django is designed such that what the user sees 1144 00:55:32,500 --> 00:55:35,020 and the code are as separated as possible such 1145 00:55:35,020 --> 00:55:38,500 that if you wanted to change the route that the user sees, 1146 00:55:38,500 --> 00:55:41,830 you wouldn't need to go into the HTML template 1147 00:55:41,830 --> 00:55:44,350 and actually change any code in order to make that possible. 1148 00:55:44,350 --> 00:55:46,766 You could change the route and leave the name in the same. 1149 00:55:46,766 --> 00:55:48,620 And then it would work just fine. 1150 00:55:48,620 --> 00:55:51,610 So now that I've named these routes, how do I actually use them? 1151 00:55:51,610 --> 00:55:55,780 Well, inside of Flight.html here, let's at the bottom offer the user a way 1152 00:55:55,780 --> 00:55:58,700 to get back to where they were before. 1153 00:55:58,700 --> 00:56:01,630 So let's add an a href which is going to be equal to something, 1154 00:56:01,630 --> 00:56:02,920 we don't know quite yet. 1155 00:56:02,920 --> 00:56:06,190 And it's going to be back to full listing, 1156 00:56:06,190 --> 00:56:08,860 taking me back to the full listing of all the flights. 1157 00:56:08,860 --> 00:56:11,265 And the link that I want to link to in Django syntax 1158 00:56:11,265 --> 00:56:13,999 is to say I want to link to a URL, and then in quotation marks-- 1159 00:56:13,999 --> 00:56:15,790 single quotation marks because I've already 1160 00:56:15,790 --> 00:56:17,470 used double quotation marks here-- 1161 00:56:17,470 --> 00:56:19,850 I'm going to give the name of the URL I want to link to. 1162 00:56:19,850 --> 00:56:22,900 So you URL index to say, when you click here, 1163 00:56:22,900 --> 00:56:26,030 take me to the URL for the index page. 1164 00:56:26,030 --> 00:56:29,200 So now if I am on this page on the flight 1 page, 1165 00:56:29,200 --> 00:56:31,930 I had this back to full listing click button, which takes me back 1166 00:56:31,930 --> 00:56:34,070 to the original Flights page. 1167 00:56:34,070 --> 00:56:37,900 Likewise, on the original Flights page, on index.html, 1168 00:56:37,900 --> 00:56:40,030 instead of just printing out the flight, I'd 1169 00:56:40,030 --> 00:56:44,320 like to link to that specific flight page. 1170 00:56:44,320 --> 00:56:48,130 And to do that, I wanted to say, URL flight, 1171 00:56:48,130 --> 00:56:51,380 because that was the name of the flight URL, but what's missing here? 1172 00:56:51,380 --> 00:56:52,858 Why is this not going to work? 1173 00:56:52,858 --> 00:56:53,941 AUDIENCE: You need the ID. 1174 00:56:53,941 --> 00:56:54,850 SPEAKER 1: Exactly. 1175 00:56:54,850 --> 00:56:57,340 I need the ID because the flight route isn't 1176 00:56:57,340 --> 00:57:01,000 just a route that stays the same anytime I refer to it by name. 1177 00:57:01,000 --> 00:57:03,280 It has this variable in it, this flight ID variable, 1178 00:57:03,280 --> 00:57:05,580 that I need to somehow provide to Django. 1179 00:57:05,580 --> 00:57:08,560 And in Django the way to do that is just include the ID right 1180 00:57:08,560 --> 00:57:09,760 after the name of the URL. 1181 00:57:09,760 --> 00:57:12,700 So URL to flight, and the argument to pass into it 1182 00:57:12,700 --> 00:57:17,970 is the flight's ID such that now if I refresh this page flight 1 and flight 2 1183 00:57:17,970 --> 00:57:18,530 are links. 1184 00:57:18,530 --> 00:57:22,060 If I click on flight 1, that takes me to the detail page for flight 1. 1185 00:57:22,060 --> 00:57:26,540 I can go back, click on flight 2, now here is the detail page for flight 2. 1186 00:57:26,540 --> 00:57:29,180 So that was linking between different pages. 1187 00:57:29,180 --> 00:57:31,621 Questions about that? 1188 00:57:31,621 --> 00:57:34,370 One other thing that I alluded to before that I'll talk about very 1189 00:57:34,370 --> 00:57:38,630 briefly is that inside of this HTML, this flight.html template 1190 00:57:38,630 --> 00:57:42,110 and my index.html template, there is a lot of repetitive code. 1191 00:57:42,110 --> 00:57:43,640 This header is basically the same. 1192 00:57:43,640 --> 00:57:45,660 I have body tags in both of them. 1193 00:57:45,660 --> 00:57:48,650 And so just like in Flask, we could use template inheritance 1194 00:57:48,650 --> 00:57:52,580 to say I want some base template from which other templates are derived from. 1195 00:57:52,580 --> 00:57:54,330 I can do the same thing in Django as well. 1196 00:57:54,330 --> 00:57:58,020 And so the way I'll do that is by creating a new template, which 1197 00:57:58,020 --> 00:57:59,930 we'll call base.html. 1198 00:57:59,930 --> 00:58:05,290 And base.html is going to contain all of this original code 1199 00:58:05,290 --> 00:58:08,840 except the body I'm just going to call block body. 1200 00:58:08,840 --> 00:58:12,740 This looks very, very similar to what Jinja syntax for the same thing is. 1201 00:58:12,740 --> 00:58:14,870 And then end block. 1202 00:58:14,870 --> 00:58:17,140 And I'll make the title-- 1203 00:58:17,140 --> 00:58:20,310 I'll actually make the title a block title as well. 1204 00:58:20,310 --> 00:58:22,280 And then end block there. 1205 00:58:22,280 --> 00:58:26,420 And so now inside of index.html rather than have all of this, 1206 00:58:26,420 --> 00:58:32,240 I can just say, first of all, I want to extend 1207 00:58:32,240 --> 00:58:37,430 the flight slash base.html template inside of block title. 1208 00:58:37,430 --> 00:58:40,340 Let me go ahead and say Flights. 1209 00:58:40,340 --> 00:58:43,760 And that's the end of that block. 1210 00:58:43,760 --> 00:58:51,210 And now inside of the body block, I have all of this content. 1211 00:58:51,210 --> 00:58:52,590 End block there. 1212 00:58:52,590 --> 00:58:55,270 And I don't need to indent this as much. 1213 00:58:55,270 --> 00:58:58,920 And so now this is my index.html page. 1214 00:58:58,920 --> 00:59:07,900 And now my flight.html will likewise extend the flight/base.html template 1215 00:59:07,900 --> 00:59:10,360 as the block title. 1216 00:59:10,360 --> 00:59:12,190 I can add in a title. 1217 00:59:12,190 --> 00:59:13,930 Before the title was just Flights. 1218 00:59:13,930 --> 00:59:16,540 I'll go ahead and be a little bit nicer about it 1219 00:59:16,540 --> 00:59:22,000 and call it flight.id so the title of the page includes the ID of the flight. 1220 00:59:22,000 --> 00:59:30,330 And then inside of the block body, I'll go ahead and include this content 1221 00:59:30,330 --> 00:59:33,810 that was previously in the body. 1222 00:59:33,810 --> 00:59:37,990 And I'll indent that just for clarity. 1223 00:59:37,990 --> 00:59:41,860 And so now what I have is the same exact thing except I've 1224 00:59:41,860 --> 00:59:44,080 divided things up a little bit into templates 1225 00:59:44,080 --> 00:59:46,720 such that my base template has all the HTML code that 1226 00:59:46,720 --> 00:59:48,550 is common to both of my files. 1227 00:59:48,550 --> 00:59:52,780 And then index.html and flight.html are able to modify those blocks 1228 00:59:52,780 --> 00:59:55,654 in much the same way as we did in Flask as well. 1229 00:59:55,654 --> 00:59:58,570 And the result is that this page looks basically the same except I now 1230 00:59:58,570 --> 01:00:01,300 have flight 2 up here in the title. 1231 01:00:01,300 --> 01:00:04,099 And if I go back, this page is basically the same as well. 1232 01:00:04,099 --> 01:00:05,890 This was just a nice organizational measure 1233 01:00:05,890 --> 01:00:10,000 to do that didn't add a whole lot of additional features to the application 1234 01:00:10,000 --> 01:00:11,900 itself. 1235 01:00:11,900 --> 01:00:12,750 But now-- go ahead. 1236 01:00:12,750 --> 01:00:15,136 AUDIENCE: [INAUDIBLE] still Jinja? 1237 01:00:15,136 --> 01:00:17,980 SPEAKER 1: The templating language is no longer Jinja. 1238 01:00:17,980 --> 01:00:19,469 It is Django's templating language. 1239 01:00:19,469 --> 01:00:22,510 Django just happens to have its own templating language that in many ways 1240 01:00:22,510 --> 01:00:23,560 resembles Jinja. 1241 01:00:23,560 --> 01:00:26,580 And the syntax for most things is almost identical. 1242 01:00:26,580 --> 01:00:29,470 And the documentation for Django's templating language is very good 1243 01:00:29,470 --> 01:00:31,090 and it's all available online. 1244 01:00:31,090 --> 01:00:32,620 We won't have time to go through all the features, 1245 01:00:32,620 --> 01:00:34,370 but there are all sorts of filters you can 1246 01:00:34,370 --> 01:00:37,120 apply to things to make things look precisely the way that you 1247 01:00:37,120 --> 01:00:37,930 want them to. 1248 01:00:37,930 --> 01:00:41,210 And it can be quite powerful in that respect. 1249 01:00:41,210 --> 01:00:45,010 So now what I want to do is think back to our original airline application 1250 01:00:45,010 --> 01:00:48,082 where, in addition to representing flights and potential airports, 1251 01:00:48,082 --> 01:00:50,290 we also wanted a way to represent passengers and have 1252 01:00:50,290 --> 01:00:52,180 passengers on individual flights. 1253 01:00:52,180 --> 01:00:56,020 And the way that we did this back in Flask was to create a table 1254 01:00:56,020 --> 01:00:59,690 called Passengers where our Passenger table, if you recall, 1255 01:00:59,690 --> 01:01:04,420 had a Flight ID column that referenced a specific flight such 1256 01:01:04,420 --> 01:01:07,210 that every passenger was associated with one flight. 1257 01:01:07,210 --> 01:01:10,700 And that was how we were able to relate passengers to flights. 1258 01:01:10,700 --> 01:01:18,240 What is a possible design flaw in that set up for flights and passengers 1259 01:01:18,240 --> 01:01:22,380 whereby in our Passengers table, we had a Flight ID column that 1260 01:01:22,380 --> 01:01:24,948 linked to one particular flight? 1261 01:01:24,948 --> 01:01:28,140 AUDIENCE: You could have multiple flights associated with a passenger. 1262 01:01:28,140 --> 01:01:28,530 SPEAKER 1: Exactly. 1263 01:01:28,530 --> 01:01:31,280 We could have multiple flights associated with the same passenger. 1264 01:01:31,280 --> 01:01:34,227 One passenger might want to be on multiple flights 1265 01:01:34,227 --> 01:01:36,060 or might be registered for multiple flights. 1266 01:01:36,060 --> 01:01:38,670 And it would be nice if we could say for Alice here, 1267 01:01:38,670 --> 01:01:40,920 what are all the flights that Alice is registered for, 1268 01:01:40,920 --> 01:01:42,500 and to be able to see them. 1269 01:01:42,500 --> 01:01:46,650 And that wouldn't be quite as easy if we just had a single table of passengers 1270 01:01:46,650 --> 01:01:50,400 where each passenger can only be associated with one single flight. 1271 01:01:50,400 --> 01:01:52,822 So how might we get around this problem? 1272 01:01:52,822 --> 01:01:54,780 How might we structure tables in order to allow 1273 01:01:54,780 --> 01:01:58,710 for this what's called a many-to-many relationship, where one passenger might 1274 01:01:58,710 --> 01:02:00,780 be associated with many different flights 1275 01:02:00,780 --> 01:02:03,881 and one flight might be associated with many different passengers? 1276 01:02:03,881 --> 01:02:06,227 1277 01:02:06,227 --> 01:02:08,310 Any thoughts on how to construct a table for that? 1278 01:02:08,310 --> 01:02:12,399 AUDIENCE: [INAUDIBLE] table that has just like two ID [INAUDIBLE].. 1279 01:02:12,399 --> 01:02:13,440 SPEAKER 1: Yeah, exactly. 1280 01:02:13,440 --> 01:02:16,170 So one conventional way to solve this is with an in-between table 1281 01:02:16,170 --> 01:02:20,250 that has two columns where we have one column for a passenger ID 1282 01:02:20,250 --> 01:02:21,561 and one column for a flight ID. 1283 01:02:21,561 --> 01:02:23,310 So we have one separate table for flights, 1284 01:02:23,310 --> 01:02:26,640 one separate table for passengers, and this in-between table that 1285 01:02:26,640 --> 01:02:28,182 maps passengers and flights together. 1286 01:02:28,182 --> 01:02:30,015 We could have as many of these relationships 1287 01:02:30,015 --> 01:02:32,550 as we want such that a flight can have multiple passengers 1288 01:02:32,550 --> 01:02:35,280 and a passenger can be on multiple different flights. 1289 01:02:35,280 --> 01:02:36,660 So that's what we'd like to do. 1290 01:02:36,660 --> 01:02:38,730 What Django's actually going to allow us to do 1291 01:02:38,730 --> 01:02:41,790 is do that without needing to worry about explicitly creating 1292 01:02:41,790 --> 01:02:45,150 the in-between table and just describing the relationship that we want, 1293 01:02:45,150 --> 01:02:47,640 describing this many-to-many relationship 1294 01:02:47,640 --> 01:02:49,840 that we want to define our models. 1295 01:02:49,840 --> 01:02:52,200 So I'm going to go ahead and open up models.py. 1296 01:02:52,200 --> 01:02:55,260 We have this existing Airport class and this existing Flight class. 1297 01:02:55,260 --> 01:02:58,260 But now what I'm going to do is add a new class called 1298 01:02:58,260 --> 01:03:02,580 Passenger which is going to be a model. 1299 01:03:02,580 --> 01:03:05,730 And a passenger is going to have, let's say, a first name which 1300 01:03:05,730 --> 01:03:09,660 will be a char field of max length of 64 again 1301 01:03:09,660 --> 01:03:14,880 and a last name which will be also a char field of max length 64. 1302 01:03:14,880 --> 01:03:17,880 And also, a passenger, if we just think about this 1303 01:03:17,880 --> 01:03:20,400 in terms of what a passenger is associated with, 1304 01:03:20,400 --> 01:03:22,650 a passenger is associated with flights. 1305 01:03:22,650 --> 01:03:26,190 They have some flights that they are on. 1306 01:03:26,190 --> 01:03:29,910 And this is not a single foreign key, not a single flight we're pointing to. 1307 01:03:29,910 --> 01:03:34,230 This is a many-to-many field that one passenger might 1308 01:03:34,230 --> 01:03:36,540 be associated with many flights, one flight 1309 01:03:36,540 --> 01:03:38,399 might be associated with many passengers. 1310 01:03:38,399 --> 01:03:41,190 So it's a many-to-many field that corresponds to what type of data? 1311 01:03:41,190 --> 01:03:42,910 Well, it corresponds to a flight. 1312 01:03:42,910 --> 01:03:46,726 I'm going to add blank equals true, just to allow for the possibility 1313 01:03:46,726 --> 01:03:48,600 that maybe a passenger is not on any flights. 1314 01:03:48,600 --> 01:03:50,020 So their flights field is blank. 1315 01:03:50,020 --> 01:03:51,730 That's certainly a possibility. 1316 01:03:51,730 --> 01:03:55,680 And I'll also add this related name, just like we had before, such that-- 1317 01:03:55,680 --> 01:03:58,410 and I'll call the related name Passengers-- 1318 01:03:58,410 --> 01:04:02,220 such that if I have a flight and I want to get at its passengers, 1319 01:04:02,220 --> 01:04:05,740 I can use this related named passengers to be able to get at that as well. 1320 01:04:05,740 --> 01:04:07,360 And we'll how that works in a moment. 1321 01:04:07,360 --> 01:04:10,980 And finally, I'll go out and add a STR function to the passenger such 1322 01:04:10,980 --> 01:04:13,810 that if I ever wanted to reference a passenger, 1323 01:04:13,810 --> 01:04:17,280 it'll just be self.first self.last. 1324 01:04:17,280 --> 01:04:21,270 We print out their full name when we want to represent a passenger. 1325 01:04:21,270 --> 01:04:22,810 So this is our Passenger class. 1326 01:04:22,810 --> 01:04:25,060 And now I would like to just add this to the database. 1327 01:04:25,060 --> 01:04:26,320 Notice I'm going to-- 1328 01:04:26,320 --> 01:04:29,340 I want-- the solution to this problem is this in-between table that 1329 01:04:29,340 --> 01:04:30,957 maps passengers and flights together. 1330 01:04:30,957 --> 01:04:33,290 But I haven't written a class for this in-between table. 1331 01:04:33,290 --> 01:04:35,790 I just said I want a many-to-many field. 1332 01:04:35,790 --> 01:04:37,920 But watch what will happen is that if I now 1333 01:04:37,920 --> 01:04:41,250 say python manage.py makemigrations, it's 1334 01:04:41,250 --> 01:04:43,590 now detected that I've created this new model Passenger. 1335 01:04:43,590 --> 01:04:45,930 It's added a new migration file for me. 1336 01:04:45,930 --> 01:04:49,620 And if I now say python manage.py, let's take a look at what the actual SQL 1337 01:04:49,620 --> 01:04:51,600 contents of this migration is. 1338 01:04:51,600 --> 01:04:54,450 So I'll do a sqlmigrate flights 003. 1339 01:04:54,450 --> 01:04:57,450 What's actually happening here, if we take a look at it, 1340 01:04:57,450 --> 01:05:00,770 is even though we only added one model what 1341 01:05:00,770 --> 01:05:05,080 Django is going to do when I apply this migration is create two tables. 1342 01:05:05,080 --> 01:05:08,410 It's creating one table here called Flights_passenger, 1343 01:05:08,410 --> 01:05:11,580 which is going to manage in the Flights app, all of the passengers. 1344 01:05:11,580 --> 01:05:15,390 And this has an ID field, a first name field, a last name field 1345 01:05:15,390 --> 01:05:16,780 just as before. 1346 01:05:16,780 --> 01:05:19,770 And we're also, Django's going to create another table called, 1347 01:05:19,770 --> 01:05:24,150 oddly enough, Flights Passenger Flights, meaning in the Flights app, 1348 01:05:24,150 --> 01:05:27,690 mapping individual passengers to individual flights which 1349 01:05:27,690 --> 01:05:33,810 has an ID field, a passenger ID field, and this other flight ID field such 1350 01:05:33,810 --> 01:05:36,550 that these tables are created for me. 1351 01:05:36,550 --> 01:05:39,180 I didn't need to worry about creating the in-between table, 1352 01:05:39,180 --> 01:05:40,830 defining the names of these columns. 1353 01:05:40,830 --> 01:05:43,800 I tell Django what my data looks like, that my passengers are 1354 01:05:43,800 --> 01:05:45,720 associated with multiple flights. 1355 01:05:45,720 --> 01:05:49,020 And Django figures out what SQL needs to run in order 1356 01:05:49,020 --> 01:05:51,910 to create the models in such a way that I can use them. 1357 01:05:51,910 --> 01:05:54,900 And so this is all designed to make it easier on you as the person 1358 01:05:54,900 --> 01:05:57,815 writing the application to not need to worry about specifically 1359 01:05:57,815 --> 01:06:00,190 what the tables look like and what the columns look like. 1360 01:06:00,190 --> 01:06:03,370 But just to be able to deal with the data that you actually want. 1361 01:06:03,370 --> 01:06:07,006 And so I'll go ahead and migrate this into the database. 1362 01:06:07,006 --> 01:06:08,880 That's going to apply the migration, actually 1363 01:06:08,880 --> 01:06:10,740 create all of these new tables. 1364 01:06:10,740 --> 01:06:16,950 And so now, if I go into the shell and say, 1365 01:06:16,950 --> 01:06:23,030 from flights.models, let's import Flight and let's import Passenger. 1366 01:06:23,030 --> 01:06:25,410 Let me go ahead and get the first flight, 1367 01:06:25,410 --> 01:06:28,680 flight.objects.get PK equals 1 to get the first flight, that's 1368 01:06:28,680 --> 01:06:30,489 our flight from New York to London. 1369 01:06:30,489 --> 01:06:32,280 And let me create a new passenger now. p is 1370 01:06:32,280 --> 01:06:35,040 going to be equal to a passenger whose first name is 1371 01:06:35,040 --> 01:06:36,700 Alice and whose last name-- 1372 01:06:36,700 --> 01:06:37,890 I'll do another A name-- 1373 01:06:37,890 --> 01:06:38,743 Adams. 1374 01:06:38,743 --> 01:06:40,920 So now I have this passenger. 1375 01:06:40,920 --> 01:06:42,990 I'm going to save this new passenger. 1376 01:06:42,990 --> 01:06:47,040 And my passenger has a flights attribute to it. 1377 01:06:47,040 --> 01:06:48,810 And so I have p.flights. 1378 01:06:48,810 --> 01:06:51,807 And so if I want to add a new flight to this passenger, 1379 01:06:51,807 --> 01:06:52,890 I can say p.flights.add f. 1380 01:06:52,890 --> 01:06:55,860 1381 01:06:55,860 --> 01:07:00,030 And now, if I do p.flights.all, for instance, 1382 01:07:00,030 --> 01:07:02,190 to query for all this passenger's flights, 1383 01:07:02,190 --> 01:07:05,279 I see that this passenger is now on this flight from New York to London. 1384 01:07:05,279 --> 01:07:07,570 And this is a query set that could be multiple flights. 1385 01:07:07,570 --> 01:07:10,950 So this passenger can now be on multiple flights potentially. 1386 01:07:10,950 --> 01:07:17,115 And likewise, if I have f, I can do f.passengers.all to get 1387 01:07:17,115 --> 01:07:19,740 all of the passengers that are on this particular flight, which 1388 01:07:19,740 --> 01:07:21,250 might be multiple as well. 1389 01:07:21,250 --> 01:07:23,700 So I've been able to encode this many-to-many relationship 1390 01:07:23,700 --> 01:07:26,010 without needing to worry about the specifics of what 1391 01:07:26,010 --> 01:07:28,564 goes into each one of these individual tables. 1392 01:07:28,564 --> 01:07:29,730 Questions about that so far? 1393 01:07:29,730 --> 01:07:32,590 1394 01:07:32,590 --> 01:07:36,820 So what I might want to do now is offer some way 1395 01:07:36,820 --> 01:07:41,270 to be able to see passengers inside the detail view of my application. 1396 01:07:41,270 --> 01:07:43,810 So inside of views.py, I might want it such 1397 01:07:43,810 --> 01:07:48,670 that in addition to displaying the flight, I also display the passengers. 1398 01:07:48,670 --> 01:07:55,190 So flight.passengers.all in order to query for all the passengers. 1399 01:07:55,190 --> 01:07:58,240 And that gets passed into my flight.html file. 1400 01:07:58,240 --> 01:08:02,200 And so inside of flight.html now, I might also want to say, 1401 01:08:02,200 --> 01:08:08,770 let's add a heading called Passengers and another unordered list 1402 01:08:08,770 --> 01:08:18,069 where for each one of my passengers in my list of passengers, 1403 01:08:18,069 --> 01:08:21,140 I display the passenger's name. 1404 01:08:21,140 --> 01:08:24,710 And Django has a special syntax, this is slightly different from Jinja, 1405 01:08:24,710 --> 01:08:27,649 called empty for what to do if the for loop never ran, 1406 01:08:27,649 --> 01:08:28,979 if nothing ever happened. 1407 01:08:28,979 --> 01:08:32,240 And here we'll just say no passengers. 1408 01:08:32,240 --> 01:08:34,399 And so I'm looping over all of my passengers, 1409 01:08:34,399 --> 01:08:36,529 just printing out the passenger name such 1410 01:08:36,529 --> 01:08:38,960 that now if I click on one of these individual links, 1411 01:08:38,960 --> 01:08:45,144 after I start up the server, I get here's the flight details and here's 1412 01:08:45,144 --> 01:08:46,060 my list of passengers. 1413 01:08:46,060 --> 01:08:47,765 I have one passenger on this flight. 1414 01:08:47,765 --> 01:08:50,890 I go back to the full listing, click on this flight that has no passengers, 1415 01:08:50,890 --> 01:08:53,899 I see that this flight has no passengers on it. 1416 01:08:53,899 --> 01:08:55,220 Questions about any of that? 1417 01:08:55,220 --> 01:08:58,879 1418 01:08:58,879 --> 01:09:01,920 One other thing we can do very quickly just to show you what this is like 1419 01:09:01,920 --> 01:09:04,880 is if I go into admin.py and say, you know 1420 01:09:04,880 --> 01:09:08,479 what, admin.site.registser.passenger, I also 1421 01:09:08,479 --> 01:09:11,020 want to be able to modify passengers on my Admin site. 1422 01:09:11,020 --> 01:09:12,920 I'll import that as well. 1423 01:09:12,920 --> 01:09:18,180 And I go to this admin link and I log in. 1424 01:09:18,180 --> 01:09:21,120 Now I see this additional passengers option where I could likewise 1425 01:09:21,120 --> 01:09:25,890 create if I wanted to add a new passenger called Bob Baker or whatever, 1426 01:09:25,890 --> 01:09:27,240 I can add this new passenger. 1427 01:09:27,240 --> 01:09:29,850 And I can also select what flights I want Bob Baker to be on. 1428 01:09:29,850 --> 01:09:33,479 I can say, I want to be on flight number 2 and flight number 1. 1429 01:09:33,479 --> 01:09:35,729 I can select multiple, but maybe just flight number 2. 1430 01:09:35,729 --> 01:09:36,420 I can save that. 1431 01:09:36,420 --> 01:09:38,450 And now Bob is on flight number 2. 1432 01:09:38,450 --> 01:09:41,774 And if I refresh this flight number 2 page, now Bob is on that flight. 1433 01:09:41,774 --> 01:09:44,399 So I'm able to use the admin interface to be able to manipulate 1434 01:09:44,399 --> 01:09:45,660 this data however I like. 1435 01:09:45,660 --> 01:09:48,899 And I didn't need to design that UI for myself. 1436 01:09:48,899 --> 01:09:50,250 Questions about any of that? 1437 01:09:50,250 --> 01:09:52,960 1438 01:09:52,960 --> 01:09:55,780 As one last edition for now to this application, 1439 01:09:55,780 --> 01:09:58,450 let's see if we can add some way for people 1440 01:09:58,450 --> 01:10:01,690 to be able to register for flights via the web UI, 1441 01:10:01,690 --> 01:10:05,960 to be able to submit a form that allows them to register for a new flight. 1442 01:10:05,960 --> 01:10:08,210 So what might that look like? 1443 01:10:08,210 --> 01:10:12,620 Well, let's go ahead and go into urls.py of my Flights app 1444 01:10:12,620 --> 01:10:15,370 and let's add a new route, the route that will happen when someone 1445 01:10:15,370 --> 01:10:18,070 tries to book a flight, for instance. 1446 01:10:18,070 --> 01:10:23,050 So the path for that will be int flight_id/book. 1447 01:10:23,050 --> 01:10:27,790 In other words, if someone is submitting a request to my URL, /2/book, 1448 01:10:27,790 --> 01:10:33,384 that will mean I want to book a ticket on flight number 2. 1449 01:10:33,384 --> 01:10:36,550 So that's going to link to the function views.book, which doesn't exist yet. 1450 01:10:36,550 --> 01:10:38,070 But I'll create it in just a moment. 1451 01:10:38,070 --> 01:10:41,810 And I'll go ahead and name this book just for good measure. 1452 01:10:41,810 --> 01:10:45,700 So now, let's go into views.py and create 1453 01:10:45,700 --> 01:10:48,760 this book function, this function that I want to happen when I try 1454 01:10:48,760 --> 01:10:50,030 and book a flight. 1455 01:10:50,030 --> 01:10:52,420 It takes in the request as its first argument. 1456 01:10:52,420 --> 01:10:55,360 It also takes in a flight ID. 1457 01:10:55,360 --> 01:10:57,910 And so what do I need to do inside this book function? 1458 01:10:57,910 --> 01:11:00,730 Well, several things could go wrong as I try and book the flight. 1459 01:11:00,730 --> 01:11:03,730 So let me try to do some things and figure out what could happen. 1460 01:11:03,730 --> 01:11:10,915 I'll say passenger_id is equal to int request.POST passenger. 1461 01:11:10,915 --> 01:11:12,790 And so I'm going to assume for now, and we'll 1462 01:11:12,790 --> 01:11:15,940 see how to implement this later, that when someone is booking a flight, 1463 01:11:15,940 --> 01:11:17,684 they're going to submit a POST request. 1464 01:11:17,684 --> 01:11:19,600 And one of the arguments in that POST request, 1465 01:11:19,600 --> 01:11:22,720 the data that passed gets passed in, is named passenger. 1466 01:11:22,720 --> 01:11:26,750 I'm going to convert that to an integer and store that as passenger_id. 1467 01:11:26,750 --> 01:11:29,710 Once I have that, now I'm going to say, well, 1468 01:11:29,710 --> 01:11:34,870 passenger better be passenger.objects.get 1469 01:11:34,870 --> 01:11:38,200 PK equals passenger_id. 1470 01:11:38,200 --> 01:11:40,960 I want to get the passenger that has that ID. 1471 01:11:40,960 --> 01:11:45,840 And in order to make that work, I need to make sure that I import Passenger 1472 01:11:45,840 --> 01:11:48,097 up here as well. 1473 01:11:48,097 --> 01:11:49,930 And I'm also going to want to get my flight. 1474 01:11:49,930 --> 01:11:54,475 So flight equals Flight.objects.get PK equal flight_id. 1475 01:11:54,475 --> 01:11:57,350 So now I tried to get the passenger ID, I tried to get the passenger, 1476 01:11:57,350 --> 01:11:58,660 I tried to get the flight. 1477 01:11:58,660 --> 01:12:01,368 And now I'll handle the possible exceptions that could be thrown, 1478 01:12:01,368 --> 01:12:02,780 the things that could go wrong. 1479 01:12:02,780 --> 01:12:04,960 So what could go wrong here? 1480 01:12:04,960 --> 01:12:07,528 Any thoughts? 1481 01:12:07,528 --> 01:12:09,778 AUDIENCE: There's no passenger with that passenger ID. 1482 01:12:09,778 --> 01:12:12,150 SPEAKER 1: There is no passenger with that passenger ID. 1483 01:12:12,150 --> 01:12:12,780 Certainly. 1484 01:12:12,780 --> 01:12:15,990 So passenger.doesnotexist. 1485 01:12:15,990 --> 01:12:18,900 And in that case, I'll return-- 1486 01:12:18,900 --> 01:12:23,150 in this case, I'll render a special HTML form, 1487 01:12:23,150 --> 01:12:27,000 error.html which I'll create which will just be my default way of displaying 1488 01:12:27,000 --> 01:12:28,680 error messages, for instance. 1489 01:12:28,680 --> 01:12:35,780 And to my error.html, I'll pass in the context of message no passenger. 1490 01:12:35,780 --> 01:12:39,960 And likewise, I'll go ahead and copy this and say, 1491 01:12:39,960 --> 01:12:42,580 if the exception was flight.doesnotexist, 1492 01:12:42,580 --> 01:12:46,620 there was no flight, then my error message will be no flight. 1493 01:12:46,620 --> 01:12:51,460 And one other thing that could go wrong in this case is a key error. 1494 01:12:51,460 --> 01:12:54,772 Any idea why I might get a key error by running this code? 1495 01:12:54,772 --> 01:13:00,010 1496 01:13:00,010 --> 01:13:02,880 So if hypothetically someone submits a POST request 1497 01:13:02,880 --> 01:13:06,480 but doesn't include the passenger data in it, for instance. 1498 01:13:06,480 --> 01:13:09,530 Or they submit a get request so I don't have the POST request, 1499 01:13:09,530 --> 01:13:13,290 then I'll get a key error in this case because there was no passenger data 1500 01:13:13,290 --> 01:13:14,430 to extract. 1501 01:13:14,430 --> 01:13:21,870 And so here I'll go ahead and also return the error.html with the message 1502 01:13:21,870 --> 01:13:22,560 no selection. 1503 01:13:22,560 --> 01:13:26,149 You didn't select a passenger, for instance. 1504 01:13:26,149 --> 01:13:28,190 So these are things that could possibly go wrong. 1505 01:13:28,190 --> 01:13:29,020 There are other things as well. 1506 01:13:29,020 --> 01:13:30,990 But for now, that will work for our purposes. 1507 01:13:30,990 --> 01:13:35,340 And what I'll do now is say, in order to book the flight, 1508 01:13:35,340 --> 01:13:38,790 let's take the passenger, let's go to their flights 1509 01:13:38,790 --> 01:13:41,940 because every passenger has flights that's associated with that passenger, 1510 01:13:41,940 --> 01:13:44,594 and add that flight. 1511 01:13:44,594 --> 01:13:46,510 And that's all the code I need in order to add 1512 01:13:46,510 --> 01:13:47,926 this new passenger to this flight. 1513 01:13:47,926 --> 01:13:51,160 I take the passenger, I take the flights that are associated with them, 1514 01:13:51,160 --> 01:13:54,170 and I add this new flight that I've just created. 1515 01:13:54,170 --> 01:13:56,670 And what I likely want to do now is redirect them somewhere, 1516 01:13:56,670 --> 01:13:58,770 redirect the user to some other page. 1517 01:13:58,770 --> 01:14:02,460 And so to do that in Django, the syntax looks like this-- 1518 01:14:02,460 --> 01:14:05,190 Httpresponsredirect. 1519 01:14:05,190 --> 01:14:06,944 And where do I want to redirect them to? 1520 01:14:06,944 --> 01:14:09,860 Well, I probably want to redirect them to this particular flight page. 1521 01:14:09,860 --> 01:14:14,100 So the syntax for getting the URL if you know 1522 01:14:14,100 --> 01:14:18,780 the name of the route you want to go to is called reverse in Django. 1523 01:14:18,780 --> 01:14:21,540 Because I want to go in the reverse direction of going 1524 01:14:21,540 --> 01:14:25,590 from the name of the URL to the actual URL. 1525 01:14:25,590 --> 01:14:29,990 So it's reverse followed by flight, which is the name of the URL 1526 01:14:29,990 --> 01:14:31,080 that I want to go to. 1527 01:14:31,080 --> 01:14:33,660 This route here has a name of flight. 1528 01:14:33,660 --> 01:14:35,076 And that's what I want to go to. 1529 01:14:35,076 --> 01:14:36,700 And it also takes additional arguments. 1530 01:14:36,700 --> 01:14:40,740 So my argument is going to be a tupple of what 1531 01:14:40,740 --> 01:14:42,480 arguments get passed into the flight. 1532 01:14:42,480 --> 01:14:47,020 And in this case, the argument is the flight ID. 1533 01:14:47,020 --> 01:14:49,460 And so I'll go ahead and pass that in as well. 1534 01:14:49,460 --> 01:14:56,640 And I will also need to up here import Httpresponseredirect and also 1535 01:14:56,640 --> 01:15:01,990 from django.urls import reverse, just to give me access 1536 01:15:01,990 --> 01:15:03,404 to that reverse function. 1537 01:15:03,404 --> 01:15:05,320 But the long story short of what this is doing 1538 01:15:05,320 --> 01:15:08,290 is I'm going to first try and extract the passenger's ID, 1539 01:15:08,290 --> 01:15:10,630 get at the passenger itself and their flight, 1540 01:15:10,630 --> 01:15:13,622 add the flight to the passenger's collection of flights 1541 01:15:13,622 --> 01:15:15,580 that they're associated with, and then redirect 1542 01:15:15,580 --> 01:15:17,840 the user back to the flight page. 1543 01:15:17,840 --> 01:15:21,040 And so now what I need to do is actually create 1544 01:15:21,040 --> 01:15:25,120 some kind of form that is going to lead to this book route. 1545 01:15:25,120 --> 01:15:31,910 So inside of flight.html, I'll go ahead and add that functionality to here. 1546 01:15:31,910 --> 01:15:37,590 So, underneath this list of passengers, I'll go ahead and add a horizontal row. 1547 01:15:37,590 --> 01:15:45,660 I'll add a new heading that is like Add a Passenger, for instance. 1548 01:15:45,660 --> 01:15:53,010 And so what I want to do now is add some sort of form here where I might say, 1549 01:15:53,010 --> 01:15:58,660 form action is where I want the form to go to. 1550 01:15:58,660 --> 01:16:02,962 So any thoughts on what belongs in the action for this form? 1551 01:16:02,962 --> 01:16:05,914 AUDIENCE: URL and then the name of [INAUDIBLE].. 1552 01:16:05,914 --> 01:16:06,650 SPEAKER 1: Yep. 1553 01:16:06,650 --> 01:16:10,950 So the name of that function was book, as the name of this particular path. 1554 01:16:10,950 --> 01:16:13,920 And I need to pass in the individual flight ID for it. 1555 01:16:13,920 --> 01:16:17,190 So it'll be book followed by flight.id. 1556 01:16:17,190 --> 01:16:20,760 And so inside this form, and the form's method that I'm submitting it via, 1557 01:16:20,760 --> 01:16:23,070 is going to be a POST method. 1558 01:16:23,070 --> 01:16:24,550 What am I going to need? 1559 01:16:24,550 --> 01:16:27,870 Well, what I probably want to do is offer some way for me 1560 01:16:27,870 --> 01:16:33,420 to select from the people that are not on this flight. 1561 01:16:33,420 --> 01:16:36,420 So all the people that are not currently passengers on this flight, 1562 01:16:36,420 --> 01:16:38,555 I want there to be some sort of select dropdown 1563 01:16:38,555 --> 01:16:41,430 where I can select this is the passenger I want to add to the flight, 1564 01:16:41,430 --> 01:16:42,900 and let me add them. 1565 01:16:42,900 --> 01:16:46,230 So before I get there, what I probably want to do 1566 01:16:46,230 --> 01:16:50,590 is up here in this flight route, when I render this template also 1567 01:16:50,590 --> 01:16:55,050 pass in not just passengers but non_passengers 1568 01:16:55,050 --> 01:16:57,630 as well, people that are not passengers on this flight. 1569 01:16:57,630 --> 01:17:00,150 And the syntax for doing that, which we'll take a look at, 1570 01:17:00,150 --> 01:17:07,980 is going to be passenger.objects.exclude flights equals flight.all. 1571 01:17:07,980 --> 01:17:10,860 And so the reason why this works, passengers.objects 1572 01:17:10,860 --> 01:17:12,694 gets me all the passenger objects. 1573 01:17:12,694 --> 01:17:14,860 And then I can additionally filter this information. 1574 01:17:14,860 --> 01:17:19,080 So if I did .filter, that would mean get me passenger objects that have 1575 01:17:19,080 --> 01:17:20,160 a particular property. 1576 01:17:20,160 --> 01:17:23,552 If I did passenger.objects.filter first equals Alice, 1577 01:17:23,552 --> 01:17:26,010 that would return to me all of the passengers whose name is 1578 01:17:26,010 --> 01:17:28,410 Alice, which in this case is just one. 1579 01:17:28,410 --> 01:17:31,650 But likewise, if I say passenger.objects.exclude, 1580 01:17:31,650 --> 01:17:35,610 that's the opposite, saying get rid of things that 1581 01:17:35,610 --> 01:17:37,510 don't have this particular property. 1582 01:17:37,510 --> 01:17:39,840 In other words, get rid of all the passengers 1583 01:17:39,840 --> 01:17:43,927 who have this particular flight already in their lists of flights. 1584 01:17:43,927 --> 01:17:45,510 Because they're already on the flight. 1585 01:17:45,510 --> 01:17:50,610 I don't need to allow them to be added to this flight again. 1586 01:17:50,610 --> 01:17:55,080 And so I'm saying, exclude from the passenger objects 1587 01:17:55,080 --> 01:17:59,160 those people and call that result non_passengers. 1588 01:17:59,160 --> 01:18:01,070 Questions so far? 1589 01:18:01,070 --> 01:18:04,460 We'll see how this all fits together in just a moment. 1590 01:18:04,460 --> 01:18:09,730 So now, for Add Passenger, one thing that I might immediately want to do 1591 01:18:09,730 --> 01:18:16,660 is say if non_passengers, and wrap this whole thing inside of an if block. 1592 01:18:16,660 --> 01:18:21,912 Because if there aren't any people that have yet to register for this flight, 1593 01:18:21,912 --> 01:18:23,620 then there is no reason to display a form 1594 01:18:23,620 --> 01:18:27,220 to allow them to sign up for the flight because there's nobody else to add. 1595 01:18:27,220 --> 01:18:31,450 And so if there really is no one, then let me just display 1596 01:18:31,450 --> 01:18:36,860 a div that says no passengers to add. 1597 01:18:36,860 --> 01:18:38,420 There's nobody left out. 1598 01:18:38,420 --> 01:18:42,140 But if there are people that could be on this flight, then what I want to do 1599 01:18:42,140 --> 01:18:46,880 is add a select dropdown whose name is going to be Passenger. 1600 01:18:46,880 --> 01:18:49,280 I'm going to have a dropdown field called Passenger where 1601 01:18:49,280 --> 01:18:51,470 I select the passenger that I want. 1602 01:18:51,470 --> 01:18:53,390 Why is it called Passenger? 1603 01:18:53,390 --> 01:18:56,970 Well, it's because in views.py, inside of my book function, 1604 01:18:56,970 --> 01:18:59,330 when I tried to extract the data from the POST request, 1605 01:18:59,330 --> 01:19:01,700 I'm looking for something whose name is passenger. 1606 01:19:01,700 --> 01:19:04,460 I want to get that data out of the POST request. 1607 01:19:04,460 --> 01:19:07,430 And so this word passenger here needs to correspond 1608 01:19:07,430 --> 01:19:11,570 with the name of the select dropdown or whatever input field of the form 1609 01:19:11,570 --> 01:19:15,710 corresponds to where the user is actually selecting their data. 1610 01:19:15,710 --> 01:19:19,000 Now I'm going to loop for passenger in non_passengers, 1611 01:19:19,000 --> 01:19:22,900 so for each one of those people that are not currently on the flight, well, 1612 01:19:22,900 --> 01:19:27,710 I want to give them the option of being selected. 1613 01:19:27,710 --> 01:19:31,630 So the value of this option is going to be this passengers.id. 1614 01:19:31,630 --> 01:19:32,950 Why is it their ID? 1615 01:19:32,950 --> 01:19:35,900 Well, it's because when I extract this information, 1616 01:19:35,900 --> 01:19:38,380 I'm saving it as passenger.id and I'm trying 1617 01:19:38,380 --> 01:19:40,120 to extract that passenger by their ID. 1618 01:19:40,120 --> 01:19:44,300 That is the data I'm using in order to extract the passenger. 1619 01:19:44,300 --> 01:19:46,924 So that's going to be the value of this option. 1620 01:19:46,924 --> 01:19:49,090 And what should actually be displayed in the option, 1621 01:19:49,090 --> 01:19:51,432 well, let me just print out the passenger's name. 1622 01:19:51,432 --> 01:19:53,140 By plugging in the passenger there, we'll 1623 01:19:53,140 --> 01:19:55,630 use the STR function associated with that passenger that 1624 01:19:55,630 --> 01:19:57,400 will just be first name, last name. 1625 01:19:57,400 --> 01:20:01,040 And that way, my dropdown will be populated with their name. 1626 01:20:01,040 --> 01:20:04,370 Then finally at the end, we'll say input type equals submit. 1627 01:20:04,370 --> 01:20:09,780 And value, what displays on the Submit button, will just be Book Flight. 1628 01:20:09,780 --> 01:20:11,350 And that will be my input route. 1629 01:20:11,350 --> 01:20:13,630 And so now assuming I haven't done anything wrong, 1630 01:20:13,630 --> 01:20:19,060 if I refresh this page now, I see flight 2, passenger is currently Bob. 1631 01:20:19,060 --> 01:20:21,160 And now I see this Add a Passenger list where 1632 01:20:21,160 --> 01:20:24,550 I have a dropdown of just Alice, only the people that are not currently 1633 01:20:24,550 --> 01:20:25,990 on flight number 2. 1634 01:20:25,990 --> 01:20:27,260 And I can now book the flight. 1635 01:20:27,260 --> 01:20:29,530 I go back to the full listing, go to number 1. 1636 01:20:29,530 --> 01:20:31,810 Alice is currently a passenger. 1637 01:20:31,810 --> 01:20:33,650 And I can add Bob to the flight. 1638 01:20:33,650 --> 01:20:37,060 And so, what I would like now is if I clicked on Book Flight 1639 01:20:37,060 --> 01:20:41,230 for that to then trigger the book route and for that to cause 1640 01:20:41,230 --> 01:20:43,114 Bob to be added to flight number 1. 1641 01:20:43,114 --> 01:20:45,030 But in Django, there's a little bit of nuance. 1642 01:20:45,030 --> 01:20:48,250 When I click Book Flight, that doesn't actually happen. 1643 01:20:48,250 --> 01:20:52,720 I get this 403, forbidden error, CSRF verification failed. 1644 01:20:52,720 --> 01:20:56,770 And so CSRF stands for Cross Site Request Forgery. 1645 01:20:56,770 --> 01:20:59,560 It's a potential type of attack, of a security vulnerability 1646 01:20:59,560 --> 01:21:02,710 in forms whereby someone might be able to forge 1647 01:21:02,710 --> 01:21:04,210 where the form was coming from. 1648 01:21:04,210 --> 01:21:07,720 And Django is built in to try and protect against these types of attacks. 1649 01:21:07,720 --> 01:21:09,580 We'll talk more about this type of security 1650 01:21:09,580 --> 01:21:11,500 when we get to the security lecture later. 1651 01:21:11,500 --> 01:21:14,710 But in particular, anytime you're dealing with a form in Django, 1652 01:21:14,710 --> 01:21:17,290 you're going to need to add a little bit of extra syntax. 1653 01:21:17,290 --> 01:21:20,740 You're just going to need to add in these curly brace 1654 01:21:20,740 --> 01:21:24,085 parentheses, csrf_token. 1655 01:21:24,085 --> 01:21:27,640 This is just going to be a special value that gets entered here such 1656 01:21:27,640 --> 01:21:31,330 that when I submit the form, this token is submitted along with it. 1657 01:21:31,330 --> 01:21:35,110 And Django's server can verify that it is, in fact, my web application that's 1658 01:21:35,110 --> 01:21:36,380 submitting this request. 1659 01:21:36,380 --> 01:21:39,130 It's just an added layer of security that isn't present in Flask 1660 01:21:39,130 --> 01:21:41,140 but that's useful in Django in order to make 1661 01:21:41,140 --> 01:21:42,940 sure our forms are even more secure. 1662 01:21:42,940 --> 01:21:44,200 No need to worry about the specifics there. 1663 01:21:44,200 --> 01:21:45,910 We'll certainly talk about it later. 1664 01:21:45,910 --> 01:21:49,660 But know that for forms, you do need to include that token there as well. 1665 01:21:49,660 --> 01:21:55,120 So now, if I go to flight 1, I see the flight's origin and destination, 1666 01:21:55,120 --> 01:21:56,470 passenger is this person. 1667 01:21:56,470 --> 01:22:00,130 If I try and add Bob to it by going to Bob and clicking Book Flight, 1668 01:22:00,130 --> 01:22:02,920 now I was taken back to the original page. 1669 01:22:02,920 --> 01:22:04,960 Bob is now on my list of passengers. 1670 01:22:04,960 --> 01:22:06,790 And under Add a Passenger, it says I have 1671 01:22:06,790 --> 01:22:10,360 no passengers to add because there is no longer any passenger that 1672 01:22:10,360 --> 01:22:13,120 is not on this flight. 1673 01:22:13,120 --> 01:22:15,940 Questions about any of that so far? 1674 01:22:15,940 --> 01:22:19,780 1675 01:22:19,780 --> 01:22:21,760 So that was us being able to create forms, 1676 01:22:21,760 --> 01:22:25,540 being able to handle get and POST requests as well, 1677 01:22:25,540 --> 01:22:31,390 and using this book function to be able to update our many-to-many relationship 1678 01:22:31,390 --> 01:22:33,290 between passengers and flights. 1679 01:22:33,290 --> 01:22:37,500 1680 01:22:37,500 --> 01:22:41,040 So with this example, if you look at the source code for the example online, 1681 01:22:41,040 --> 01:22:43,581 you'll see that I do a couple other things with this example, 1682 01:22:43,581 --> 01:22:45,870 in particular, adding static files like CSS files 1683 01:22:45,870 --> 01:22:48,150 and customizing the admin interface a little bit. 1684 01:22:48,150 --> 01:22:50,620 We'll probably talk a little more about that next week. 1685 01:22:50,620 --> 01:22:53,670 But for now, this will give you the basic idea of the Django application. 1686 01:22:53,670 --> 01:22:56,370 But one other thing that I wanted to talk about 1687 01:22:56,370 --> 01:23:00,570 with regards to Django's features is the log in and authentication system 1688 01:23:00,570 --> 01:23:01,800 that comes built into Django. 1689 01:23:01,800 --> 01:23:04,633 So you probably remember that when we were looking at Django's admin 1690 01:23:04,633 --> 01:23:07,470 interface, we went to slash admin. 1691 01:23:07,470 --> 01:23:11,340 In addition to seeing these models that we wrote, this Airports, Flights, 1692 01:23:11,340 --> 01:23:14,230 and Passengers model and being able add and manipulate that, 1693 01:23:14,230 --> 01:23:16,950 we also have these users, for instance, that 1694 01:23:16,950 --> 01:23:20,400 are part of this authentication authorization app, this app 1695 01:23:20,400 --> 01:23:23,070 that I didn't create that comes built into Django. 1696 01:23:23,070 --> 01:23:25,070 This app is designed to make it easy for you 1697 01:23:25,070 --> 01:23:27,540 as the web application developer to handle things 1698 01:23:27,540 --> 01:23:32,010 like user log in and registration and making sure that users stay logged in 1699 01:23:32,010 --> 01:23:33,660 and making sure users can log out. 1700 01:23:33,660 --> 01:23:35,730 It comes built in with all of that functionality 1701 01:23:35,730 --> 01:23:38,010 because so many applications need it and use it. 1702 01:23:38,010 --> 01:23:42,150 And so unlike in Project 1, for instance, that Book application where 1703 01:23:42,150 --> 01:23:44,490 people had to log in and rate books where 1704 01:23:44,490 --> 01:23:47,301 you needed to build out that user model for yourself, the log in 1705 01:23:47,301 --> 01:23:49,800 and log out systems, you had to write all that for yourself. 1706 01:23:49,800 --> 01:23:52,240 Django comes out with most of this out of the box. 1707 01:23:52,240 --> 01:23:54,690 And so what I'll do now is show you an example 1708 01:23:54,690 --> 01:23:58,680 of us using Django's authentication model to handle things like log 1709 01:23:58,680 --> 01:24:02,040 in and log out such that when you need to write an application in Django, 1710 01:24:02,040 --> 01:24:05,041 as you will for Project 3, you'll be able to take advantage of this 1711 01:24:05,041 --> 01:24:08,040 and not need to go through nearly as much effort as you did in Project 1 1712 01:24:08,040 --> 01:24:11,640 to be able to design log in and log out functionality for an application 1713 01:24:11,640 --> 01:24:13,350 because it is so common. 1714 01:24:13,350 --> 01:24:17,070 So I'm going to go now to a different application. 1715 01:24:17,070 --> 01:24:19,650 I'm going to go into the authentication application. 1716 01:24:19,650 --> 01:24:21,190 And we'll go in and open this up. 1717 01:24:21,190 --> 01:24:23,910 And this is just another Django project inside 1718 01:24:23,910 --> 01:24:26,920 of which is a single app that I created called Users. 1719 01:24:26,920 --> 01:24:33,540 And we'll take a look at the URLs that are present first inside 1720 01:24:33,540 --> 01:24:35,520 of this application. 1721 01:24:35,520 --> 01:24:37,680 So URLs that I have inside my Users application 1722 01:24:37,680 --> 01:24:40,380 are a default route that just takes me to the index page 1723 01:24:40,380 --> 01:24:42,090 and then I have a special log in route. 1724 01:24:42,090 --> 01:24:45,630 If I go to /login, that is going to take me to the login view. 1725 01:24:45,630 --> 01:24:48,630 Log ou it's going to take me to the log out view. 1726 01:24:48,630 --> 01:24:55,770 And let me go ahead and show you what's actually happening inside of views.py, 1727 01:24:55,770 --> 01:24:57,370 inside of this application. 1728 01:24:57,370 --> 01:25:02,820 So up at the top, I import a whole bunch of interesting and useful features 1729 01:25:02,820 --> 01:25:04,860 from Django's default packages. 1730 01:25:04,860 --> 01:25:06,840 But in particular, line one is of note. 1731 01:25:06,840 --> 01:25:10,050 From django.contrib.auth, that is the package 1732 01:25:10,050 --> 01:25:13,330 that corresponds to Django's authentication library. 1733 01:25:13,330 --> 01:25:16,470 So this is what contains-- 1734 01:25:16,470 --> 01:25:21,810 the user model is contained inside of django.contrib.auth.models, 1735 01:25:21,810 --> 01:25:23,220 and these interesting functions. 1736 01:25:23,220 --> 01:25:27,520 Authenticate, log in, and log out our functions written for us by Django 1737 01:25:27,520 --> 01:25:29,230 that we can now use. 1738 01:25:29,230 --> 01:25:33,390 So what's happening inside of index, this function? 1739 01:25:33,390 --> 01:25:37,260 This is just the default route when someone goes to my Django application. 1740 01:25:37,260 --> 01:25:40,890 If not, request.user.isauthenticated. 1741 01:25:40,890 --> 01:25:42,930 This is a feature that comes with Django. 1742 01:25:42,930 --> 01:25:47,280 This request.user.isauthenticated evaluates to either true or false. 1743 01:25:47,280 --> 01:25:49,800 True if the user has been authenticated, they've logged in. 1744 01:25:49,800 --> 01:25:51,190 False, otherwise. 1745 01:25:51,190 --> 01:25:56,160 So if the user is authenticated, then I'm going to go ahead and return 1746 01:25:56,160 --> 01:25:59,940 renderinglogin.html, meaning they have now logged in-- 1747 01:25:59,940 --> 01:26:00,870 or sorry. 1748 01:26:00,870 --> 01:26:03,430 If the user is not authenticated, in other words, 1749 01:26:03,430 --> 01:26:05,820 the user has not yet logged in, then I want 1750 01:26:05,820 --> 01:26:07,690 to display the login form for the user. 1751 01:26:07,690 --> 01:26:10,980 So I'm going to render the login.html page. 1752 01:26:10,980 --> 01:26:14,969 And I'm going to say, pass in message none because maybe my login page gets 1753 01:26:14,969 --> 01:26:17,760 passed in a message if someone types in their password incorrectly, 1754 01:26:17,760 --> 01:26:18,430 for instance. 1755 01:26:18,430 --> 01:26:22,380 And we'll take a look at what login.html looks like in just a moment. 1756 01:26:22,380 --> 01:26:26,312 But otherwise, if this wasn't the case, if the user is, in fact, authenticated, 1757 01:26:26,312 --> 01:26:28,020 they have logged in, then let me go ahead 1758 01:26:28,020 --> 01:26:31,560 and just get the user by using request.user, saving 1759 01:26:31,560 --> 01:26:35,790 that inside the context, and returning the user.html template, 1760 01:26:35,790 --> 01:26:37,510 passing in that context as well. 1761 01:26:37,510 --> 01:26:39,660 And so all of these things of request.user 1762 01:26:39,660 --> 01:26:41,970 and request.user.isauthenticated, these are 1763 01:26:41,970 --> 01:26:44,012 things that come built in for me in Django 1764 01:26:44,012 --> 01:26:45,720 that I don't need to worry about writing. 1765 01:26:45,720 --> 01:26:48,660 I can just use this out of the box. 1766 01:26:48,660 --> 01:26:52,760 Questions about the index route so far? 1767 01:26:52,760 --> 01:26:56,620 Let's take a look at log in and log out. 1768 01:26:56,620 --> 01:26:59,582 So log in is going to be a form submission. 1769 01:26:59,582 --> 01:27:01,790 Someone is going to type in a user name and password. 1770 01:27:01,790 --> 01:27:03,100 They're going to click Log in. 1771 01:27:03,100 --> 01:27:06,170 And that is going to trigger, ideally, them being logged in. 1772 01:27:06,170 --> 01:27:09,250 So let me first get their username by extracting the user 1773 01:27:09,250 --> 01:27:10,960 name from their POST request. 1774 01:27:10,960 --> 01:27:14,860 I might want to put this in a try except to say if there was no user name 1775 01:27:14,860 --> 01:27:18,190 key, that's going to cause some kind of error, and I might want to handle that. 1776 01:27:18,190 --> 01:27:22,220 But for now, I'm just assuming their username and password will be in there. 1777 01:27:22,220 --> 01:27:26,360 Next to password, I say request.POST extract the password. 1778 01:27:26,360 --> 01:27:29,150 And now in order to authenticate the user, 1779 01:27:29,150 --> 01:27:31,400 it's as simple as calling this authenticate function, 1780 01:27:31,400 --> 01:27:35,090 this function that is given to me by Django where I pass in three things. 1781 01:27:35,090 --> 01:27:36,620 I first pass in the request. 1782 01:27:36,620 --> 01:27:38,000 I pass in their username. 1783 01:27:38,000 --> 01:27:39,650 And I pass in their password. 1784 01:27:39,650 --> 01:27:42,530 And it's going to return for me the user. 1785 01:27:42,530 --> 01:27:46,730 Or if it failed for some reason, it's going to return none, no user, to me 1786 01:27:46,730 --> 01:27:49,100 if there was no successful authentication. 1787 01:27:49,100 --> 01:27:51,990 So if the user is not none, in other words, 1788 01:27:51,990 --> 01:27:55,220 if a user came back from this request, then 1789 01:27:55,220 --> 01:27:57,140 that means the authentication was successful. 1790 01:27:57,140 --> 01:27:58,580 Let me actually log them in. 1791 01:27:58,580 --> 01:28:00,984 To log them in, I just call Django's log in function, 1792 01:28:00,984 --> 01:28:02,150 which is given to me, again. 1793 01:28:02,150 --> 01:28:05,540 It's built into Django, passing in again, the request and the user 1794 01:28:05,540 --> 01:28:06,590 to log in. 1795 01:28:06,590 --> 01:28:10,010 And then I'm going to redirect the user back to the index page, back 1796 01:28:10,010 --> 01:28:15,100 to that original default route of the page to show them their user page 1797 01:28:15,100 --> 01:28:16,790 up there. 1798 01:28:16,790 --> 01:28:19,440 Else, in other words, if user is none, in other words 1799 01:28:19,440 --> 01:28:23,240 the authenticate function failed, there wasn't a successful authentication, 1800 01:28:23,240 --> 01:28:26,510 then let me render the login page again, but this time 1801 01:28:26,510 --> 01:28:29,270 pass in a message that says, invalid credentials. 1802 01:28:29,270 --> 01:28:31,550 It says invalid credentials as the context 1803 01:28:31,550 --> 01:28:34,000 that I'm passing into the login page. 1804 01:28:34,000 --> 01:28:35,720 Questions about that log in route? 1805 01:28:35,720 --> 01:28:36,324 Yeah? 1806 01:28:36,324 --> 01:28:38,644 AUDIENCE: Why does, for example, the login method, 1807 01:28:38,644 --> 01:28:41,428 why does it need the request? 1808 01:28:41,428 --> 01:28:43,920 SPEAKER 1: So the request object-- 1809 01:28:43,920 --> 01:28:45,920 so the question was, why do we pass the request 1810 01:28:45,920 --> 01:28:48,500 object when we are trying to log someone in. 1811 01:28:48,500 --> 01:28:51,460 So the request object in Django contains a lot of information. 1812 01:28:51,460 --> 01:28:56,480 It contains information about the current session cookies. 1813 01:28:56,480 --> 01:28:59,910 It contains information about who is currently logged in, for instance, 1814 01:28:59,910 --> 01:29:01,400 if anyone is currently logged in. 1815 01:29:01,400 --> 01:29:05,790 And so in order to be able to modify things like request.user, for instance, 1816 01:29:05,790 --> 01:29:08,904 you might think that login needs access to that request object 1817 01:29:08,904 --> 01:29:11,070 in order to make sure that log in can be successful. 1818 01:29:11,070 --> 01:29:12,972 And this request object is very frequently 1819 01:29:12,972 --> 01:29:14,930 passed around because a lot of Django functions 1820 01:29:14,930 --> 01:29:17,490 need access to that request to work successfully. 1821 01:29:17,490 --> 01:29:21,050 So render, for instance, also requires us to pass in that request as well. 1822 01:29:21,050 --> 01:29:23,660 It's a common paradigm in Django to require that request 1823 01:29:23,660 --> 01:29:26,690 in several of the functions. 1824 01:29:26,690 --> 01:29:29,630 So at the end of that, we render invalid credentials 1825 01:29:29,630 --> 01:29:31,410 if they typed in their user name wrong. 1826 01:29:31,410 --> 01:29:34,520 And on the user page presumably once they've logged in 1827 01:29:34,520 --> 01:29:36,270 they'll have the ability to log out. 1828 01:29:36,270 --> 01:29:38,869 And what does log out look like? 1829 01:29:38,869 --> 01:29:40,035 AUDIENCE: I have a question. 1830 01:29:40,035 --> 01:29:41,013 SPEAKER 1: Yeah? 1831 01:29:41,013 --> 01:29:42,789 AUDIENCE: Is there a session object? 1832 01:29:42,789 --> 01:29:44,330 SPEAKER 1: Is there a session object? 1833 01:29:44,330 --> 01:29:46,910 Yes, there is a-- so the question is, is there a session object. 1834 01:29:46,910 --> 01:29:47,410 There is. 1835 01:29:47,410 --> 01:29:49,310 Django does have support for sessions. 1836 01:29:49,310 --> 01:29:51,851 We're probably not going have a chance to talk about it here. 1837 01:29:51,851 --> 01:29:57,240 But if you look at the settings.py page for this entire application, 1838 01:29:57,240 --> 01:30:00,140 you'll notice that one of the default installed applications 1839 01:30:00,140 --> 01:30:04,370 that comes with Django is this Sessions application that's explicitly designed 1840 01:30:04,370 --> 01:30:06,077 for helping to manage sessions. 1841 01:30:06,077 --> 01:30:07,910 And if you go to Django's documentation, you 1842 01:30:07,910 --> 01:30:11,127 can find pretty clear instructions for how to use these 1843 01:30:11,127 --> 01:30:12,710 and how to take advantage of Sessions. 1844 01:30:12,710 --> 01:30:17,030 But just like Flask does have sessions, you can use sessions in Django as well. 1845 01:30:17,030 --> 01:30:19,970 But unlike Flask, where we needed to explicitly 1846 01:30:19,970 --> 01:30:24,350 set like session square bracket user ID to say this user is logged in, 1847 01:30:24,350 --> 01:30:27,272 and we had to manually manipulate the session, in large part in Django 1848 01:30:27,272 --> 01:30:28,730 you don't need to worry about that. 1849 01:30:28,730 --> 01:30:33,380 Because Django will take care of that for you via this log 1850 01:30:33,380 --> 01:30:36,900 in and log out function that's given to us by the Authentication app. 1851 01:30:36,900 --> 01:30:41,070 So I never needed to explicitly put the user ID inside of a session variable, 1852 01:30:41,070 --> 01:30:42,779 for instance, in order to make this work. 1853 01:30:42,779 --> 01:30:45,611 Certainly if you wanted to store other things inside of the session, 1854 01:30:45,611 --> 01:30:46,182 you could. 1855 01:30:46,182 --> 01:30:48,890 But for log in and authentication, that's not strictly necessary. 1856 01:30:48,890 --> 01:30:54,829 AUDIENCE: Does it keep the request scope across requests? 1857 01:30:54,829 --> 01:30:55,870 SPEAKER 1: Good question. 1858 01:30:55,870 --> 01:30:58,040 So does it keep the request scope across requests? 1859 01:30:58,040 --> 01:31:01,740 Each request is a different request because it's a different HTTP 1860 01:31:01,740 --> 01:31:03,290 request to a different page. 1861 01:31:03,290 --> 01:31:05,614 But if the user is logged in, that is saved 1862 01:31:05,614 --> 01:31:07,530 in the session much in the same way that Flask 1863 01:31:07,530 --> 01:31:10,730 does it such that if I log in and refresh the page or close the page 1864 01:31:10,730 --> 01:31:14,880 and then reload it, the request will still have the user associated with it. 1865 01:31:14,880 --> 01:31:16,040 It'll still be logged in. 1866 01:31:16,040 --> 01:31:20,630 And using the Authentication app, you can modify and configure it such 1867 01:31:20,630 --> 01:31:22,629 that there is like a maximum expiration time, 1868 01:31:22,629 --> 01:31:25,670 after a certain point the user is automatically logged out, for instance. 1869 01:31:25,670 --> 01:31:27,980 Django gives you a bunch of these options 1870 01:31:27,980 --> 01:31:30,960 for how to configure the users and sessions the way you want to. 1871 01:31:30,960 --> 01:31:32,372 Yeah? 1872 01:31:32,372 --> 01:31:35,288 AUDIENCE: On the httpresponseredirect, why did you 1873 01:31:35,288 --> 01:31:37,861 use that rathering than just rendering [INAUDIBLE]?? 1874 01:31:37,861 --> 01:31:39,080 SPEAKER 1: Oh, good question. 1875 01:31:39,080 --> 01:31:42,800 So the question is, why am I using responseredirect rather than just 1876 01:31:42,800 --> 01:31:44,649 rendering the index page directly. 1877 01:31:44,649 --> 01:31:46,940 The answer is, I certainly could have just rendered it. 1878 01:31:46,940 --> 01:31:49,670 But if, in fact, the index page were more complicated, 1879 01:31:49,670 --> 01:31:52,400 if there was more logic in rendering the index page where 1880 01:31:52,400 --> 01:31:56,170 for instance for my flight's index page, in order to render it, 1881 01:31:56,170 --> 01:31:58,910 it wasn't as simple as just rendering index.html. 1882 01:31:58,910 --> 01:32:00,860 I had to first query for all the flights, 1883 01:32:00,860 --> 01:32:03,290 put that inside of the context, and then render it. 1884 01:32:03,290 --> 01:32:07,520 So to allow for the possibility that the index page might get more complicated 1885 01:32:07,520 --> 01:32:10,460 in the future, I just want a redirect to index such 1886 01:32:10,460 --> 01:32:14,030 that the index function can take care of any additional complexities of querying 1887 01:32:14,030 --> 01:32:17,210 the database or performing computations that it might need to do 1888 01:32:17,210 --> 01:32:19,443 before I actually render that template. 1889 01:32:19,443 --> 01:32:19,942 Yeah? 1890 01:32:19,942 --> 01:32:21,304 AUDIENCE: What is the reverse here? 1891 01:32:21,304 --> 01:32:22,540 SPEAKER 1: Oh, good question. 1892 01:32:22,540 --> 01:32:24,820 Question is, what is the reverse here. 1893 01:32:24,820 --> 01:32:29,110 So when I redirect somewhere, I need to redirect to a URL 1894 01:32:29,110 --> 01:32:34,300 but Django generally doesn't like us putting URLs inside of views.py 1895 01:32:34,300 --> 01:32:35,230 for instance. 1896 01:32:35,230 --> 01:32:38,650 Because the idea is that we want to keep things as separate as possible. 1897 01:32:38,650 --> 01:32:41,890 Django separates its projects into distinct applications. 1898 01:32:41,890 --> 01:32:45,520 Within applications, it separates URLs from the actual view functions. 1899 01:32:45,520 --> 01:32:50,140 And so it's generally good Django design practice to in the URLs 1900 01:32:50,140 --> 01:32:54,320 associate the route itself with the name. 1901 01:32:54,320 --> 01:32:57,610 And then if we want to extract the route from having a name, 1902 01:32:57,610 --> 01:33:00,040 that's where the reverse function comes in. 1903 01:33:00,040 --> 01:33:03,235 It takes index, this name, and gives me back the route that I 1904 01:33:03,235 --> 01:33:04,610 would need in order to get there. 1905 01:33:04,610 --> 01:33:07,310 1906 01:33:07,310 --> 01:33:09,730 And finally, log out, this log out view, is just 1907 01:33:09,730 --> 01:33:12,940 going to call the log out function, which again is built 1908 01:33:12,940 --> 01:33:15,580 into Django in django.contrib.auth. 1909 01:33:15,580 --> 01:33:18,430 And that's going to log the current user out and say 1910 01:33:18,430 --> 01:33:20,124 that they are now logged out. 1911 01:33:20,124 --> 01:33:21,790 So what does this look like in practice? 1912 01:33:21,790 --> 01:33:27,710 Using just this code, I can now go ahead and run the server. 1913 01:33:27,710 --> 01:33:30,240 Or actually, let me show you the HTML files first. 1914 01:33:30,240 --> 01:33:33,550 I'll show login.html, which is fairly straightforward. 1915 01:33:33,550 --> 01:33:36,250 It displays a header that says, log in. 1916 01:33:36,250 --> 01:33:39,250 If there was a message like invalid credentials, for instance, 1917 01:33:39,250 --> 01:33:43,270 it displays that inside of a div up at the top. 1918 01:33:43,270 --> 01:33:46,166 Then I have a form whose action is this login route. 1919 01:33:46,166 --> 01:33:48,040 So when I click the form and submit the form, 1920 01:33:48,040 --> 01:33:49,660 it will take me to the login route. 1921 01:33:49,660 --> 01:33:52,880 I have this token for security and an input field for a username, 1922 01:33:52,880 --> 01:33:56,860 input field for a password, and a button to actually log in. 1923 01:33:56,860 --> 01:34:02,310 Then on the user page, it's just going to say, hello to user.firstname. 1924 01:34:02,310 --> 01:34:05,260 Again, user is a model that's been created for me by Django. 1925 01:34:05,260 --> 01:34:08,920 It by default has fields like first name, last name, user name, 1926 01:34:08,920 --> 01:34:12,430 email address, and like are you an administrator of the site or not. 1927 01:34:12,430 --> 01:34:15,520 It is possible, if you want to, to extend the existing user class, 1928 01:34:15,520 --> 01:34:18,280 to add additional attributes to the user if you want to. 1929 01:34:18,280 --> 01:34:20,290 Though it's often not recommended to do that. 1930 01:34:20,290 --> 01:34:21,831 But certainly something you could do. 1931 01:34:21,831 --> 01:34:23,750 But first name is built in to Django. 1932 01:34:23,750 --> 01:34:24,680 Username is built in. 1933 01:34:24,680 --> 01:34:26,846 So this is is currently logged in as this user name. 1934 01:34:26,846 --> 01:34:29,110 And if I want to log out, I can click on this link. 1935 01:34:29,110 --> 01:34:31,270 That will take me to the log out route. 1936 01:34:31,270 --> 01:34:36,970 And so now, if I go to this default route, I was not logged in. 1937 01:34:36,970 --> 01:34:39,900 So it took me to this login page first of all 1938 01:34:39,900 --> 01:34:41,675 where I can now type in my username. 1939 01:34:41,675 --> 01:34:43,800 And I already created an account, but I'll show you 1940 01:34:43,800 --> 01:34:45,460 how to do that in just a moment. 1941 01:34:45,460 --> 01:34:48,600 And if I type in an incorrect password and click Login, 1942 01:34:48,600 --> 01:34:52,290 it says invalid credentials by re-rendering this login page. 1943 01:34:52,290 --> 01:34:55,410 If I type in my correct password, then it takes me 1944 01:34:55,410 --> 01:34:57,870 to this user page that says, hello to my first name, 1945 01:34:57,870 --> 01:35:00,300 currently logged in as-- there is my user name. 1946 01:35:00,300 --> 01:35:02,040 And this Log Out button will log me out. 1947 01:35:02,040 --> 01:35:05,871 And again, if I close this page, reopen it later, it keeps me logged in. 1948 01:35:05,871 --> 01:35:07,620 The user stays logged in and you configure 1949 01:35:07,620 --> 01:35:09,400 the details of how that works. 1950 01:35:09,400 --> 01:35:12,150 And then if I click Log Out, now I'm logged back out and back 1951 01:35:12,150 --> 01:35:14,050 at the login page. 1952 01:35:14,050 --> 01:35:15,930 So, how do you actually create users? 1953 01:35:15,930 --> 01:35:19,110 Presumably in your application and one thing you'll have to do in Project 3 1954 01:35:19,110 --> 01:35:21,690 is allow for some way of registering new users. 1955 01:35:21,690 --> 01:35:24,410 Well, that just means adding a new user to the database. 1956 01:35:24,410 --> 01:35:26,620 So multiple ways you can do this. 1957 01:35:26,620 --> 01:35:30,030 One way is by going into the admin interface. 1958 01:35:30,030 --> 01:35:34,437 If I log in with my username and password-- 1959 01:35:34,437 --> 01:35:35,770 oh, this is not a staff account. 1960 01:35:35,770 --> 01:35:37,603 So if you had a superuser account, you could 1961 01:35:37,603 --> 01:35:42,090 log into the admin interface using that superuser account and modify things. 1962 01:35:42,090 --> 01:35:46,320 But you can also make the modifications using the shell. 1963 01:35:46,320 --> 01:35:49,440 So I'll show you that, python manage.py shell. 1964 01:35:49,440 --> 01:35:54,540 And we'll say from django.contrib.auth-- 1965 01:35:54,540 --> 01:35:58,805 remember django.contrib.auth is the name of that app that handles 1966 01:35:58,805 --> 01:36:01,680 authentication-- we'll do .models because we want their models and we 1967 01:36:01,680 --> 01:36:03,390 want to import user. 1968 01:36:03,390 --> 01:36:05,985 And then if we want to create a user, I can say user equals 1969 01:36:05,985 --> 01:36:10,530 User.objects.create_user, it's a function that creates a user. 1970 01:36:10,530 --> 01:36:11,820 And it takes three arguments. 1971 01:36:11,820 --> 01:36:15,300 It takes the user's user name, an email address, and a password. 1972 01:36:15,300 --> 01:36:17,610 So I go ahead and say Alice as the username. 1973 01:36:17,610 --> 01:36:21,030 We'll use alice@something.com as the email address. 1974 01:36:21,030 --> 01:36:25,440 And for the password, we'll just say Alice12345. 1975 01:36:25,440 --> 01:36:26,420 That's the password. 1976 01:36:26,420 --> 01:36:28,470 And so that's all we need to do in order to create a user. 1977 01:36:28,470 --> 01:36:31,095 And once I've created that user, I can modify properties of it. 1978 01:36:31,095 --> 01:36:34,080 I can say user.firstname is going to be equal to Alice 1979 01:36:34,080 --> 01:36:35,640 with a capital A for instance. 1980 01:36:35,640 --> 01:36:38,380 And then user.save at the end to save that user. 1981 01:36:38,380 --> 01:36:41,610 And now I've created a new user taking advantage of this User model 1982 01:36:41,610 --> 01:36:44,070 that's given to me by Django. 1983 01:36:44,070 --> 01:36:47,220 So now that that user is created, if I go python manage.py run 1984 01:36:47,220 --> 01:36:50,712 server to start up my web server again, and then go to that URL, 1985 01:36:50,712 --> 01:36:52,420 I can now log in using those credentials. 1986 01:36:52,420 --> 01:36:55,390 Alice is the username, Alice12345 as the password, 1987 01:36:55,390 --> 01:36:57,480 and now I'm logged in as Alice. 1988 01:36:57,480 --> 01:37:00,696 1989 01:37:00,696 --> 01:37:03,070 Then with the last couple minutes, what I thought we'd do 1990 01:37:03,070 --> 01:37:07,031 is it takes some time to talk a little bit about Project 3, 1991 01:37:07,031 --> 01:37:08,530 which is going to be released today. 1992 01:37:08,530 --> 01:37:09,940 And what Project 3 is going to be about is 1993 01:37:09,940 --> 01:37:12,541 it's going to be about building an application in Django 1994 01:37:12,541 --> 01:37:15,790 and taking advantage of the features we saw here, taking advantage of the fact 1995 01:37:15,790 --> 01:37:19,330 that we can build a registration and log in and log out system 1996 01:37:19,330 --> 01:37:22,630 just by using the functions that were given to us without needing to build 1997 01:37:22,630 --> 01:37:25,120 out those models for ourself, taking advantage of the fact 1998 01:37:25,120 --> 01:37:28,510 that we can use Django's admin interface to be able to very easily add 1999 01:37:28,510 --> 01:37:31,270 and manipulate data without needing to actually build out 2000 01:37:31,270 --> 01:37:34,540 a page that lets me add things and edit things and delete things. 2001 01:37:34,540 --> 01:37:39,370 And what you're going to be doing is building the web application 2002 01:37:39,370 --> 01:37:42,657 for handling online orders of a pizza restaurant. 2003 01:37:42,657 --> 01:37:45,240 And one particular pizza restaurant in particularly, actually. 2004 01:37:45,240 --> 01:37:49,900 It will be Pinocchio's Pizza which is quite a popular pizza 2005 01:37:49,900 --> 01:37:52,045 place in Cambridge. 2006 01:37:52,045 --> 01:37:53,920 And so what we're going to give you access to 2007 01:37:53,920 --> 01:37:56,770 is Pinocchio's Pizza's menu of all of their different types 2008 01:37:56,770 --> 01:37:59,170 of pizzas and sandwiches and such. 2009 01:37:59,170 --> 01:38:02,680 And your job is going to be able to design a web application that 2010 01:38:02,680 --> 01:38:06,250 allows users to first of all register and log in and log out the website. 2011 01:38:06,250 --> 01:38:09,700 But once they're on it, to be able to then go in and place 2012 01:38:09,700 --> 01:38:13,510 an order by adding one or more items to their shopping cart 2013 01:38:13,510 --> 01:38:16,400 and then checking out such that you can then place that order. 2014 01:38:16,400 --> 01:38:18,400 And so the first thing that you're going to want 2015 01:38:18,400 --> 01:38:22,990 to do when thinking about designing this web application 2016 01:38:22,990 --> 01:38:25,990 is really taking a look at this menu that we'll give you access to 2017 01:38:25,990 --> 01:38:29,170 and figuring out what are the different models that you 2018 01:38:29,170 --> 01:38:33,410 might want to create in order to represent all of this information. 2019 01:38:33,410 --> 01:38:36,167 And so we saw a whole bunch of ways to relate different tables 2020 01:38:36,167 --> 01:38:37,000 to each other today. 2021 01:38:37,000 --> 01:38:40,540 We looked at just tables that have different fields for themselves. 2022 01:38:40,540 --> 01:38:42,700 But we also looked at foreign keys that let 2023 01:38:42,700 --> 01:38:45,760 us relate one object to potentially many objects 2024 01:38:45,760 --> 01:38:49,019 where multiple different flights can be correspond-- 2025 01:38:49,019 --> 01:38:51,310 an airport can correspond to multiple different flights 2026 01:38:51,310 --> 01:38:53,600 where a flight has an origin and a destination. 2027 01:38:53,600 --> 01:38:56,260 We looked at a lot of many-to-many relationships 2028 01:38:56,260 --> 01:38:59,644 whereby we had multiple different passengers that 2029 01:38:59,644 --> 01:39:01,810 could be on multiple different flights in any number 2030 01:39:01,810 --> 01:39:03,140 of different combinations. 2031 01:39:03,140 --> 01:39:06,490 So you might want to give some thought to here are different types of pizza, 2032 01:39:06,490 --> 01:39:10,460 but also different sizes, where any individual pizza might have one, two, 2033 01:39:10,460 --> 01:39:12,220 or three different types of toppings. 2034 01:39:12,220 --> 01:39:16,000 And figuring out what forms those data should take, 2035 01:39:16,000 --> 01:39:18,040 what the relationship between them should be 2036 01:39:18,040 --> 01:39:19,910 is going to be a helpful good first step. 2037 01:39:19,910 --> 01:39:23,260 And once you've created those models, when it comes time for the restaurant 2038 01:39:23,260 --> 01:39:25,450 owner or the site administrator in your case 2039 01:39:25,450 --> 01:39:30,070 to actually go about populating the menu that the user then sees, 2040 01:39:30,070 --> 01:39:33,070 rather than have to build out a web interface that lets a site 2041 01:39:33,070 --> 01:39:35,770 administrator type in, here is a new topping 2042 01:39:35,770 --> 01:39:38,020 that I want to now allow for Canadian bacon 2043 01:39:38,020 --> 01:39:40,480 to be offered as a topping for my menu, you 2044 01:39:40,480 --> 01:39:43,690 can just go into Django's admin user interface, which is built for you, 2045 01:39:43,690 --> 01:39:46,450 and ideally be able to just add of topping 2046 01:39:46,450 --> 01:39:49,330 very easily using the interface that's given for you there. 2047 01:39:49,330 --> 01:39:52,810 And so, that's ultimately going to be the goal of Project 3, 2048 01:39:52,810 --> 01:39:55,000 to be able to take advantage of the features 2049 01:39:55,000 --> 01:39:58,540 that Django gives you in order to simplify the process of building 2050 01:39:58,540 --> 01:40:00,827 an application like this. 2051 01:40:00,827 --> 01:40:02,410 And that will be released later today. 2052 01:40:02,410 --> 01:40:07,600 But questions about that at a high level before we wrap up for today? 2053 01:40:07,600 --> 01:40:11,029 And certainly, once the specification's out feel free to email the staff 2054 01:40:11,029 --> 01:40:12,820 or reach out on the [INAUDIBLE] if you have 2055 01:40:12,820 --> 01:40:16,369 further questions about any of that. 2056 01:40:16,369 --> 01:40:19,410 So that was sort of a look at Django and the features that Django offers. 2057 01:40:19,410 --> 01:40:21,493 It looked very similar to a Flask, especially when 2058 01:40:21,493 --> 01:40:24,450 it comes to looking at rendering templates and having functions 2059 01:40:24,450 --> 01:40:28,936 and having HTML files where we had these Jinja-like templates that were actually 2060 01:40:28,936 --> 01:40:30,310 in a slightly different language. 2061 01:40:30,310 --> 01:40:33,330 What you'll ultimately, hopefully find is that Django is quite a bit 2062 01:40:33,330 --> 01:40:36,030 more powerful, that it gives you a lot more out of the box, 2063 01:40:36,030 --> 01:40:39,660 that it gives you the ability to deal with more complicated relationships 2064 01:40:39,660 --> 01:40:43,320 between data much more easily, that it makes it much more easy for you to be 2065 01:40:43,320 --> 01:40:47,681 able to add and edit and update and delete existing entries that exist 2066 01:40:47,681 --> 01:40:49,680 inside of your database, that it makes it easier 2067 01:40:49,680 --> 01:40:52,260 to make modifications to your database, to change a database, 2068 01:40:52,260 --> 01:40:54,468 and then migrate those changes so that you don't need 2069 01:40:54,468 --> 01:40:57,840 to worry about actually applying the Alter Table or Create Table 2070 01:40:57,840 --> 01:40:59,070 commands on your own, 2071 01:40:59,070 --> 01:41:01,560 and that ultimately it's going to make it easier 2072 01:41:01,560 --> 01:41:04,500 to build more sophisticated applications by giving you more 2073 01:41:04,500 --> 01:41:06,372 of these features right out of the box. 2074 01:41:06,372 --> 01:41:07,830 So that was a first look at Django. 2075 01:41:07,830 --> 01:41:11,900 We'll wrap up today today and best of luck with Project 3. 2076 01:41:11,900 --> 01:41:14,385