1 00:00:00,000 --> 00:00:02,460 [MUSIC PLAYING] 2 00:00:02,460 --> 00:00:15,707 3 00:00:15,707 --> 00:00:19,040 BRIAN YU: Welcome back, everyone, to web programming with Python and JavaScript. 4 00:00:19,040 --> 00:00:22,310 So picking up where we left off last time-- we were talking about data 5 00:00:22,310 --> 00:00:25,040 and, ultimately, how to represent data in our web applications-- 6 00:00:25,040 --> 00:00:26,777 ultimately in the form of databases. 7 00:00:26,777 --> 00:00:28,610 So we looked a lot at this example of trying 8 00:00:28,610 --> 00:00:31,449 to represent airlines and the things that an airline might 9 00:00:31,449 --> 00:00:34,490 need to keep track of-- keeping track of different flights, each of which 10 00:00:34,490 --> 00:00:38,690 has an origin and a destination and a duration for how long that flight is. 11 00:00:38,690 --> 00:00:41,510 And today, we're going to dive in even more into databases, 12 00:00:41,510 --> 00:00:44,930 looking at how we can take advantage of a full-featured programming language, 13 00:00:44,930 --> 00:00:49,232 like Python, to be able to interact with databases all the more powerfully, 14 00:00:49,232 --> 00:00:52,190 take advantage of the features that the Python programming language has 15 00:00:52,190 --> 00:00:54,899 to offer, to let us interact with the data in a way that's 16 00:00:54,899 --> 00:00:55,940 a little more convenient. 17 00:00:55,940 --> 00:00:58,065 And then a little later on today, we'll take a look 18 00:00:58,065 --> 00:01:01,220 at APIs, Application Programming Interfaces-- ways 19 00:01:01,220 --> 00:01:05,239 that we can allow other applications to interact with our application and ways 20 00:01:05,239 --> 00:01:09,110 that we can use APIs written by other people to get access to other data 21 00:01:09,110 --> 00:01:09,630 as well. 22 00:01:09,630 --> 00:01:12,950 And this come into play as you begin to work on project 1, which is ultimately 23 00:01:12,950 --> 00:01:17,059 about building a system that lets you rate reviews for books 24 00:01:17,059 --> 00:01:19,850 and look up reviews for books that exist out there on the internet. 25 00:01:19,850 --> 00:01:22,610 And as part of that, you'll be using an existing API 26 00:01:22,610 --> 00:01:25,940 to get at reviews that other people have written elsewhere on the internet 27 00:01:25,940 --> 00:01:30,050 and, also, to build an API of your own so that users of your website 28 00:01:30,050 --> 00:01:33,710 can use your API to be able to access the rating data that is ultimately 29 00:01:33,710 --> 00:01:36,450 going to be inside of your own database. 30 00:01:36,450 --> 00:01:39,020 So in order to interact with this database, in the past, 31 00:01:39,020 --> 00:01:42,260 we've been using SQL or S-Q-L, a language that 32 00:01:42,260 --> 00:01:45,980 lets us interact with data by performing commands like Insert to insert rows 33 00:01:45,980 --> 00:01:49,310 into a table, or Update to take existing rows from the table 34 00:01:49,310 --> 00:01:53,240 and update the contents of those tables, Delete to get rid of them, 35 00:01:53,240 --> 00:01:56,220 and Select in order to extract data out of those tables. 36 00:01:56,220 --> 00:01:59,000 But what we're going to turn to now is to take a look at this 37 00:01:59,000 --> 00:02:00,620 from a more Python-based approach. 38 00:02:00,620 --> 00:02:03,410 And in particular, before we dive back into databases, 39 00:02:03,410 --> 00:02:06,718 we're first just going to talk about object-oriented programming, which 40 00:02:06,718 --> 00:02:08,509 is a type of programming that Python allows 41 00:02:08,509 --> 00:02:11,690 us to do, along with a bunch of other programming languages, that primarily 42 00:02:11,690 --> 00:02:14,990 focuses on programming-- thinking in the concept of objects, 43 00:02:14,990 --> 00:02:17,760 where you can think of an object as just a thing. 44 00:02:17,760 --> 00:02:20,360 For example, an object in one of our applications 45 00:02:20,360 --> 00:02:22,110 might be a flight, for example. 46 00:02:22,110 --> 00:02:24,260 We might have an object for each individual flight. 47 00:02:24,260 --> 00:02:27,350 We might have an object for each individual passenger. 48 00:02:27,350 --> 00:02:30,050 And what object-oriented programming allows us to do 49 00:02:30,050 --> 00:02:34,160 is to create what are called "classes" or the generic idea 50 00:02:34,160 --> 00:02:35,430 for a generic object. 51 00:02:35,430 --> 00:02:37,550 So we'll have a Flight class that is going 52 00:02:37,550 --> 00:02:40,640 to describe all of the components that make up a flight. 53 00:02:40,640 --> 00:02:43,490 And from that Flight class, we can also describe things 54 00:02:43,490 --> 00:02:45,660 that we want our flights to be able to do. 55 00:02:45,660 --> 00:02:47,760 We would like for our Flight class, for example, 56 00:02:47,760 --> 00:02:51,140 to be able to easily add a passenger to that flight. 57 00:02:51,140 --> 00:02:52,910 And likewise, we'll have a Passenger class 58 00:02:52,910 --> 00:02:55,640 that is going to represent the generic idea of a passenger, where 59 00:02:55,640 --> 00:02:57,931 that passenger is going to have a name and they'll also 60 00:02:57,931 --> 00:03:00,800 be associated with the flight that they're currently registered for. 61 00:03:00,800 --> 00:03:03,530 And so using object-oriented programming in Python, 62 00:03:03,530 --> 00:03:07,799 we'll be able to programmatically devise these ideas inside of code. 63 00:03:07,799 --> 00:03:09,590 And so let's take a look at what that would 64 00:03:09,590 --> 00:03:12,530 look like by looking at a simple example of a Python class. 65 00:03:12,530 --> 00:03:15,200 We took a look at this earlier when we first introduced Python. 66 00:03:15,200 --> 00:03:18,777 But now, we'll begin to dive a little deeper into how Python classes work 67 00:03:18,777 --> 00:03:21,110 and how they operate, so that we can see how we can then 68 00:03:21,110 --> 00:03:23,690 use those ideas to apply them to the databases 69 00:03:23,690 --> 00:03:26,970 that we'll be building out inside of our web applications. 70 00:03:26,970 --> 00:03:31,640 So the first thing we'll look at is that Class is 0.py. 71 00:03:31,640 --> 00:03:35,660 And all this file does is define a Python class. 72 00:03:35,660 --> 00:03:39,860 In this case, we're just defining the generic idea for what a flight is. 73 00:03:39,860 --> 00:03:42,911 And so up here on line 1, we say class Flight 74 00:03:42,911 --> 00:03:44,660 to mean we're going to create a new Python 75 00:03:44,660 --> 00:03:47,930 class called Flight that is going to represent flights inside 76 00:03:47,930 --> 00:03:49,730 of our application. 77 00:03:49,730 --> 00:03:52,960 Here on line 3 is what's called a method. 78 00:03:52,960 --> 00:03:54,800 You can think of a method as a function that 79 00:03:54,800 --> 00:03:57,050 is performed on individual flights. 80 00:03:57,050 --> 00:04:00,110 And in this case, this is a special method built into Python, 81 00:04:00,110 --> 00:04:03,710 called the init method, which is going to describe what happens what we first 82 00:04:03,710 --> 00:04:05,039 want to create a flight. 83 00:04:05,039 --> 00:04:08,080 When we don't have a flight before and we want to create our first Flight 84 00:04:08,080 --> 00:04:10,939 object, we'll call this init method. 85 00:04:10,939 --> 00:04:13,980 And what this init method will do is it will take a couple of parameters. 86 00:04:13,980 --> 00:04:15,790 It will take self-- 87 00:04:15,790 --> 00:04:18,980 so methods in Python classes will, generally, all 88 00:04:18,980 --> 00:04:20,779 have self as their first argument. 89 00:04:20,779 --> 00:04:24,482 That self first argument just refers to the objects that we are working with. 90 00:04:24,482 --> 00:04:26,690 And you'll see more examples of this once we actually 91 00:04:26,690 --> 00:04:29,000 start using this class. 92 00:04:29,000 --> 00:04:32,300 Then we also have a bunch of other arguments to this method. 93 00:04:32,300 --> 00:04:35,210 We have origin and destination and duration. 94 00:04:35,210 --> 00:04:37,610 Because when we create a new flight, those 95 00:04:37,610 --> 00:04:40,680 are the different fields that we're going to want to populate. 96 00:04:40,680 --> 00:04:44,060 That's the information that we want to store about any particular flight. 97 00:04:44,060 --> 00:04:47,780 We want to store that flight's origin, its destination, and its duration. 98 00:04:47,780 --> 00:04:50,450 And in order to store them, we'll store them inside 99 00:04:50,450 --> 00:04:52,830 of properties inside of our object. 100 00:04:52,830 --> 00:04:57,740 So if self is our object, then we'll set the property self.origin 101 00:04:57,740 --> 00:05:00,260 to be equal to whatever this origin is, whatever 102 00:05:00,260 --> 00:05:02,930 we pass in to this init method. 103 00:05:02,930 --> 00:05:07,670 And likewise, we'll do the same thing for destination and for duration. 104 00:05:07,670 --> 00:05:11,399 That way, when we create a flight, all this init method is doing is saying, 105 00:05:11,399 --> 00:05:13,190 when we create a flight, I want to provide, 106 00:05:13,190 --> 00:05:16,340 as input, the origin, destination, and duration of the flight. 107 00:05:16,340 --> 00:05:19,970 And then I want to save that information inside of variables 108 00:05:19,970 --> 00:05:22,040 contained within our Flight object. 109 00:05:22,040 --> 00:05:26,690 And the names for those properties will be Origin, Destination, and Duration. 110 00:05:26,690 --> 00:05:28,985 So how then do we actually take this class 111 00:05:28,985 --> 00:05:30,860 and actually use it for something meaningful? 112 00:05:30,860 --> 00:05:32,690 So far, it just seems very abstract. 113 00:05:32,690 --> 00:05:35,810 Well, let's take a look at classes1.py, where 114 00:05:35,810 --> 00:05:38,280 you'll see an example of how we might actually use this. 115 00:05:38,280 --> 00:05:42,180 So the first six lines of classes1.py does exactly the same thing. 116 00:05:42,180 --> 00:05:46,220 We're just defining this generic class to represent flights inside 117 00:05:46,220 --> 00:05:47,600 of our Python program. 118 00:05:47,600 --> 00:05:49,670 But now, here, we have a main function, which 119 00:05:49,670 --> 00:05:51,086 is going to do a couple of things. 120 00:05:51,086 --> 00:05:52,280 So let's take a look at it. 121 00:05:52,280 --> 00:05:56,060 So inside of our main function, the first thing we're doing here on line 12 122 00:05:56,060 --> 00:05:57,900 is creating a new flight. 123 00:05:57,900 --> 00:06:01,700 And so to create a new flight, we're going to use the name of the class. 124 00:06:01,700 --> 00:06:04,280 The name of the class is Flight with a capital F. 125 00:06:04,280 --> 00:06:06,470 And then in parentheses, we're going to specify 126 00:06:06,470 --> 00:06:11,030 those parameters that we defined as part of the init method of our Flight class. 127 00:06:11,030 --> 00:06:13,670 And so Python knows that, when I want to create a new flight, 128 00:06:13,670 --> 00:06:17,030 it's going to call that init method to create a new Flight object. 129 00:06:17,030 --> 00:06:19,380 And we're going to pass in those specific parameters. 130 00:06:19,380 --> 00:06:21,930 We're going to say, we'll create a flight whose origin is 131 00:06:21,930 --> 00:06:24,680 New York, whose destination is Paris. 132 00:06:24,680 --> 00:06:28,010 And the duration is going to be 540 minutes in this case. 133 00:06:28,010 --> 00:06:30,650 And we're going to save that newly-created object 134 00:06:30,650 --> 00:06:32,520 inside of this variable called F. 135 00:06:32,520 --> 00:06:35,240 So F is a variable of type Flight. 136 00:06:35,240 --> 00:06:39,350 Just like before we were able to have variables that were integers or strings 137 00:06:39,350 --> 00:06:43,280 or lists of other things, we're now able to create a variable that is of a type 138 00:06:43,280 --> 00:06:44,220 that we've created. 139 00:06:44,220 --> 00:06:49,470 It's type is this class, Flight, that we defined earlier in this file. 140 00:06:49,470 --> 00:06:51,470 So that's how we've now created this flight. 141 00:06:51,470 --> 00:06:55,340 And now, because our flight has stored information about itself-- 142 00:06:55,340 --> 00:06:58,490 it's stored information about its origin, about its destination, 143 00:06:58,490 --> 00:07:02,040 about its duration-- we can now access those individual properties. 144 00:07:02,040 --> 00:07:05,780 So if I want to change the value of this flight's duration, 145 00:07:05,780 --> 00:07:09,050 because the flight was delayed and now it's going to take a little bit longer, 146 00:07:09,050 --> 00:07:13,880 I can access the duration of my flight, F, by writing F.duration. 147 00:07:13,880 --> 00:07:16,700 And then plus equals 10 is just Python syntax for, 148 00:07:16,700 --> 00:07:19,520 increment the value of the duration of the flight by 10. 149 00:07:19,520 --> 00:07:23,649 I could have equivalently written f.duration=f.duration+10. 150 00:07:23,649 --> 00:07:25,440 And that would mean exactly the same thing. 151 00:07:25,440 --> 00:07:29,330 But the idea here is that I'm updating this value of duration 152 00:07:29,330 --> 00:07:31,280 in order to reflect some new value. 153 00:07:31,280 --> 00:07:32,750 So I can access them that way. 154 00:07:32,750 --> 00:07:36,140 And likewise, I can also just read them by calling them 155 00:07:36,140 --> 00:07:39,590 by name-- f.origin, f.destination, and f.duration. 156 00:07:39,590 --> 00:07:41,540 Saying Print in front of each one is just 157 00:07:41,540 --> 00:07:45,080 going to print out this flight's origin, print out the flight's destination, 158 00:07:45,080 --> 00:07:48,270 and print out the duration of the flight as well. 159 00:07:48,270 --> 00:07:55,190 So when I go to run this code and I run Python classes1.py, 160 00:07:55,190 --> 00:07:56,887 what I get is one on each line-- 161 00:07:56,887 --> 00:07:57,970 the origin of the flight-- 162 00:07:57,970 --> 00:07:59,760 New York-- the destination of the flight-- 163 00:07:59,760 --> 00:08:03,770 Paris-- and 550, which was the duration of the flight-- 164 00:08:03,770 --> 00:08:08,810 540 with 10 added to it, as we updated the value of that duration 165 00:08:08,810 --> 00:08:11,030 property of the flight. 166 00:08:11,030 --> 00:08:13,160 Questions about how that worked? 167 00:08:13,160 --> 00:08:18,260 About how we were able to use this class definition for what a flight is up 168 00:08:18,260 --> 00:08:20,420 in the first six lines of this file and then 169 00:08:20,420 --> 00:08:24,920 use that inside of our main function to create a flight, update its properties, 170 00:08:24,920 --> 00:08:28,415 and then print out information about the flight afterwards? 171 00:08:28,415 --> 00:08:28,915 Yeah? 172 00:08:28,915 --> 00:08:31,825 AUDIENCE: So do we have to use "self" always? 173 00:08:31,825 --> 00:08:32,900 [INAUDIBLE] 174 00:08:32,900 --> 00:08:33,900 BRIAN YU: Good question. 175 00:08:33,900 --> 00:08:35,179 So the question is, what is this self? 176 00:08:35,179 --> 00:08:36,320 Do we have to use it? 177 00:08:36,320 --> 00:08:42,440 So self is-- whenever we want to call methods on individual flights, 178 00:08:42,440 --> 00:08:44,900 we're going to need to have that Self perimeter there, 179 00:08:44,900 --> 00:08:48,470 so that we're able to update specific properties of the flight. 180 00:08:48,470 --> 00:08:51,820 So we can update the origin of this specific object. 181 00:08:51,820 --> 00:08:53,570 And you'll see this in a couple of minutes 182 00:08:53,570 --> 00:08:55,570 when we start to look at examples where we might 183 00:08:55,570 --> 00:08:57,262 start to have more than one flight. 184 00:08:57,262 --> 00:08:58,220 So I create one flight. 185 00:08:58,220 --> 00:08:59,960 And I create another Flight object. 186 00:08:59,960 --> 00:09:04,220 And now, if I want to access the destination of a flight inside of one 187 00:09:04,220 --> 00:09:07,700 of these methods, well, these methods need to have some idea 188 00:09:07,700 --> 00:09:09,660 of, which flight am I referring to? 189 00:09:09,660 --> 00:09:11,630 And so that's what this Self property is doing. 190 00:09:11,630 --> 00:09:15,470 It's telling the method which specific flight I'm referring to, when 191 00:09:15,470 --> 00:09:18,860 I want to use it inside of a method. 192 00:09:18,860 --> 00:09:24,164 And we never actually need to pass self into the methods when we use them. 193 00:09:24,164 --> 00:09:27,080 Notice that when I created the flight down here, I didn't have to say, 194 00:09:27,080 --> 00:09:28,490 self equals anything. 195 00:09:28,490 --> 00:09:31,090 That wasn't part of the syntax of creating a new flight. 196 00:09:31,090 --> 00:09:32,540 That self is just implicit. 197 00:09:32,540 --> 00:09:35,599 The first argument of the method is just assumed to be Self 198 00:09:35,599 --> 00:09:37,640 and it will be put there automatically by Python. 199 00:09:37,640 --> 00:09:41,236 AUDIENCE: So it has to be S-E-L-F always? 200 00:09:41,236 --> 00:09:44,110 BRIAN YU: OK, so the question is, does it have to be exactly S-E-L-F? 201 00:09:44,110 --> 00:09:45,274 That word "self"? 202 00:09:45,274 --> 00:09:45,940 Technically, no. 203 00:09:45,940 --> 00:09:47,500 You could probably get away with using something else. 204 00:09:47,500 --> 00:09:49,990 But by convention, we'll usually just call it "self" 205 00:09:49,990 --> 00:09:52,417 when dealing with Python classes. 206 00:09:52,417 --> 00:09:53,000 Good question. 207 00:09:53,000 --> 00:09:54,080 Other things? 208 00:09:54,080 --> 00:09:54,787 Yeah? 209 00:09:54,787 --> 00:09:58,160 AUDIENCE: Do we need an init method? 210 00:09:58,160 --> 00:10:01,060 BRIAN YU: Good question-- do you need an init method? 211 00:10:01,060 --> 00:10:04,780 Strictly speaking, you could create a class that didn't have an init method. 212 00:10:04,780 --> 00:10:07,540 So I could have created a class that just had nothing in it. 213 00:10:07,540 --> 00:10:10,360 And in Python, the way to say that we want nothing in here 214 00:10:10,360 --> 00:10:13,159 and just keep going is to use the word "pass." 215 00:10:13,159 --> 00:10:15,700 That would have created just an empty class that doesn't have 216 00:10:15,700 --> 00:10:17,320 any init method or any methods at all. 217 00:10:17,320 --> 00:10:19,090 And I could still assign properties to it. 218 00:10:19,090 --> 00:10:22,000 But in order to allow me to do syntax like this where, 219 00:10:22,000 --> 00:10:25,240 when I create a new flight, I specify the origin and the destination 220 00:10:25,240 --> 00:10:27,820 and duration, then you need the init method there, 221 00:10:27,820 --> 00:10:31,337 in order to tell the class what to do when you create a new objects. 222 00:10:31,337 --> 00:10:32,920 So conventionally, we'll see it there. 223 00:10:32,920 --> 00:10:35,980 But later on today, we'll actually see examples where not all of our classes 224 00:10:35,980 --> 00:10:38,140 will have that init method, because we don't always need it. 225 00:10:38,140 --> 00:10:40,530 AUDIENCE: Can you put the last slide in [INAUDIBLE]?? 226 00:10:40,530 --> 00:10:43,870 Why do we need this equal statement, name equal to main? 227 00:10:43,870 --> 00:10:44,870 BRIAN YU: Good question. 228 00:10:44,870 --> 00:10:48,050 So the question is, why do we need this last line here, this if name equals 229 00:10:48,050 --> 00:10:49,120 equals main? 230 00:10:49,120 --> 00:10:53,489 So just naturally, Python is going to execute our code from top to bottom. 231 00:10:53,489 --> 00:10:56,030 So it's just going to read the top and go down to the bottom. 232 00:10:56,030 --> 00:10:58,460 And all of the relevant and interesting code 233 00:10:58,460 --> 00:11:02,870 that we're doing here in this program is contained inside of this main function. 234 00:11:02,870 --> 00:11:05,690 And so, unless I ever call that main function, 235 00:11:05,690 --> 00:11:07,650 this code is never going to run. 236 00:11:07,650 --> 00:11:12,980 And so what these last few lines here are doing is saying, if__name__=main-- 237 00:11:12,980 --> 00:11:16,630 this is saying, effectively, if I am running this particular file, 238 00:11:16,630 --> 00:11:20,520 if I am running the classes1.py file, what should I do? 239 00:11:20,520 --> 00:11:23,292 And in this case, we're just going to call the main function. 240 00:11:23,292 --> 00:11:25,250 And this is a convention that you'll frequently 241 00:11:25,250 --> 00:11:27,632 see whenever we're writing short scripts in Python. 242 00:11:27,632 --> 00:11:30,548 AUDIENCE: If I remove these lines, like, if I remove this if statement 243 00:11:30,548 --> 00:11:33,860 and directly call main, that can still [INAUDIBLE].. 244 00:11:33,860 --> 00:11:36,590 BRIAN YU: OK, so the question is, if I remove the if statement 245 00:11:36,590 --> 00:11:39,110 and just called main, would that work? 246 00:11:39,110 --> 00:11:41,962 And yes, if I just ran this, it would successfully call main, 247 00:11:41,962 --> 00:11:44,670 because it reads it top to bottom and it calls the main function. 248 00:11:44,670 --> 00:11:46,850 The reason why we generally wouldn't want to do that 249 00:11:46,850 --> 00:11:50,420 is, if ever we wanted to import this file into some other file, 250 00:11:50,420 --> 00:11:54,200 if I wanted to use my Flight class inside of some other Python file, 251 00:11:54,200 --> 00:11:58,220 if I tried to import classes1.py, it would read the code top to bottom. 252 00:11:58,220 --> 00:11:59,387 It would hit this main line. 253 00:11:59,387 --> 00:12:02,095 And then it would try to run the main function, which I might not 254 00:12:02,095 --> 00:12:05,030 want to happen if I don't want this particular flight to be created 255 00:12:05,030 --> 00:12:07,050 every time I import the file somewhere. 256 00:12:07,050 --> 00:12:11,720 And so, the "if name equals main" syntax says, only when I'm running this file 257 00:12:11,720 --> 00:12:14,030 and not when I'm importing it into some other file, 258 00:12:14,030 --> 00:12:16,370 then I want to run this particular function. 259 00:12:16,370 --> 00:12:17,700 Good questions. 260 00:12:17,700 --> 00:12:22,490 OK, so now that we have this init method that's just a default method that's 261 00:12:22,490 --> 00:12:25,790 used to create a new object, let's start looking at other methods 262 00:12:25,790 --> 00:12:28,600 we could use in order to add functionality to our flights. 263 00:12:28,600 --> 00:12:32,220 So we would like our flights to be able to do more things. 264 00:12:32,220 --> 00:12:35,240 So let's take a look at classes2.py. 265 00:12:35,240 --> 00:12:38,670 And in this case, we noticed that, in the previous example, 266 00:12:38,670 --> 00:12:41,190 we had to, after creating the flight, print out 267 00:12:41,190 --> 00:12:42,740 information about that flight. 268 00:12:42,740 --> 00:12:47,180 We had to say, print the duration, print the origin, print the destination. 269 00:12:47,180 --> 00:12:50,240 Maybe we would like for the flight itself to know how 270 00:12:50,240 --> 00:12:52,400 to print information out about itself. 271 00:12:52,400 --> 00:12:53,890 And so how might we do that? 272 00:12:53,890 --> 00:12:55,640 So the first six lines here are identical. 273 00:12:55,640 --> 00:12:57,348 We're just creating that init method that 274 00:12:57,348 --> 00:12:59,540 allows us to create a brand new flight. 275 00:12:59,540 --> 00:13:01,940 But down here on line 8, we've added a new method 276 00:13:01,940 --> 00:13:04,010 that we've created for this Flight class that's 277 00:13:04,010 --> 00:13:06,980 going to give the flight some additional functionality. 278 00:13:06,980 --> 00:13:09,200 In particular, we're calling it Print Info. 279 00:13:09,200 --> 00:13:11,670 And this Print Info method, which takes self, once again-- 280 00:13:11,670 --> 00:13:14,090 the object that we're going to be operating on-- 281 00:13:14,090 --> 00:13:16,722 is going to serve the purpose of printing out 282 00:13:16,722 --> 00:13:17,930 information about the flight. 283 00:13:17,930 --> 00:13:21,140 So the flight will now know how to print out its origin and destination 284 00:13:21,140 --> 00:13:22,400 and duration. 285 00:13:22,400 --> 00:13:23,520 How does it do that? 286 00:13:23,520 --> 00:13:26,240 Well, inside of the Print Info method, we're saying, 287 00:13:26,240 --> 00:13:28,530 here's what we should do whenever we print info. 288 00:13:28,530 --> 00:13:30,170 Print this formatted string-- 289 00:13:30,170 --> 00:13:31,250 Flight origin. 290 00:13:31,250 --> 00:13:32,440 And what is the origin? 291 00:13:32,440 --> 00:13:35,630 Well, I have access to this variable self that represents the object 292 00:13:35,630 --> 00:13:36,950 that I'm operating on. 293 00:13:36,950 --> 00:13:38,540 So Flight origin colon-- 294 00:13:38,540 --> 00:13:42,080 and then, remember, these curly braces are used in formatted strings to say, 295 00:13:42,080 --> 00:13:43,351 insert some variable here. 296 00:13:43,351 --> 00:13:46,100 And in particular, in this case, the variable that we're inserting 297 00:13:46,100 --> 00:13:47,750 is self.origin. 298 00:13:47,750 --> 00:13:51,465 Self refers to the flight that we're trying to print information. 299 00:13:51,465 --> 00:13:53,900 .origin will access that origin property. 300 00:13:53,900 --> 00:13:57,090 And likewise, we do the same thing for destination and duration. 301 00:13:57,090 --> 00:14:00,450 And now, this is part of the definition of the Flight class. 302 00:14:00,450 --> 00:14:04,400 So now, anytime I create a new flight using this class definition, 303 00:14:04,400 --> 00:14:06,950 we're going to be able to use this Print Info method, 304 00:14:06,950 --> 00:14:10,362 because every flight will now know how to print out information about itself. 305 00:14:10,362 --> 00:14:12,320 And so, now this seems like more lines of code. 306 00:14:12,320 --> 00:14:13,580 Why would we want to do this? 307 00:14:13,580 --> 00:14:15,990 But this is now useful if we have multiple flights. 308 00:14:15,990 --> 00:14:18,510 Now, all of them will have that same functionality. 309 00:14:18,510 --> 00:14:22,560 So if I look at what's going on inside of my Main method here, 310 00:14:22,560 --> 00:14:23,960 now I have two flights. 311 00:14:23,960 --> 00:14:28,170 So on line 16, I have f1, my first flight-- is going to be a flight. 312 00:14:28,170 --> 00:14:31,790 And this is just using that init method syntax to create a new flight-- 313 00:14:31,790 --> 00:14:32,690 origin is New York. 314 00:14:32,690 --> 00:14:33,980 Destination is Paris. 315 00:14:33,980 --> 00:14:36,140 Duration is 540 minutes. 316 00:14:36,140 --> 00:14:40,115 And then I'm going to call upon that method, using that same dot syntax. 317 00:14:40,115 --> 00:14:43,550 So whenever I want to access a property of an object 318 00:14:43,550 --> 00:14:46,940 or call on a method of that object to run one of the functions 319 00:14:46,940 --> 00:14:50,360 that I've defined inside that Flight class, we'll use the dot syntax. 320 00:14:50,360 --> 00:14:54,860 And so f1.print_info is going to say, take my object, F1-- 321 00:14:54,860 --> 00:14:55,880 this is a flight-- 322 00:14:55,880 --> 00:14:58,880 and print information about it by calling that Print Info method 323 00:14:58,880 --> 00:15:01,370 that we defined earlier in the file. 324 00:15:01,370 --> 00:15:04,160 And likewise, we'll do the same thing for F2, 325 00:15:04,160 --> 00:15:07,520 another flight with a different origin, a different destination, 326 00:15:07,520 --> 00:15:08,810 and a different duration. 327 00:15:08,810 --> 00:15:11,900 Let's print out information for that flight as well by calling 328 00:15:11,900 --> 00:15:13,460 f2.print_info. 329 00:15:13,460 --> 00:15:18,500 And so when we call f1.print_info, then the self in this Print Info method will 330 00:15:18,500 --> 00:15:20,240 be f1, that first flight. 331 00:15:20,240 --> 00:15:23,820 And when we call it the second time, self will be f2, the second flight. 332 00:15:23,820 --> 00:15:29,060 And so self.origin, self.destination and self.duration will refer to f1 and f2 333 00:15:29,060 --> 00:15:31,950 respectively, when we call upon those methods. 334 00:15:31,950 --> 00:15:37,520 So now, all I need to do, if I run Python classes2.py, 335 00:15:37,520 --> 00:15:40,720 is I'll see, on the first three lines, the origin, destination, 336 00:15:40,720 --> 00:15:42,550 and duration of the first flight and then, 337 00:15:42,550 --> 00:15:46,720 following that, the origin, destination, and duration of the second flight. 338 00:15:46,720 --> 00:15:49,390 Because both of these flights now have that ability 339 00:15:49,390 --> 00:15:51,831 to print out information about themselves. 340 00:15:51,831 --> 00:15:52,330 Yeah? 341 00:15:52,330 --> 00:15:55,138 AUDIENCE: Do you actually have to say origin equals New York? 342 00:15:55,138 --> 00:15:58,039 Or can you go, New York, Paris, [INAUDIBLE]?? 343 00:15:58,039 --> 00:15:59,080 BRIAN YU: Great question. 344 00:15:59,080 --> 00:16:01,450 So the question is, did I need to specify origin equals, 345 00:16:01,450 --> 00:16:03,280 destination equals, duration equals? 346 00:16:03,280 --> 00:16:04,870 Strictly speaking, no. 347 00:16:04,870 --> 00:16:08,470 Because Python assumes that I can just pass in the parameters in order. 348 00:16:08,470 --> 00:16:13,705 I could have said, just New York, Paris, and 550. 349 00:16:13,705 --> 00:16:16,330 I added the parameters there, which are optional but allowable, 350 00:16:16,330 --> 00:16:19,317 just to be very explicit about, what are the names of each parameter? 351 00:16:19,317 --> 00:16:22,150 And another thing that allows me to do is put them in whatever order 352 00:16:22,150 --> 00:16:23,509 that I want to, if I wanted to. 353 00:16:23,509 --> 00:16:25,300 But if you know the order of the parameters 354 00:16:25,300 --> 00:16:27,383 and you put those parameters in the correct order, 355 00:16:27,383 --> 00:16:30,788 then-- strictly speaking-- you don't need those names in front of them. 356 00:16:30,788 --> 00:16:31,282 AUDIENCE: So then that-- 357 00:16:31,282 --> 00:16:31,907 BRIAN YU: Yeah? 358 00:16:31,907 --> 00:16:35,234 AUDIENCE: --means, when we define the class first, 359 00:16:35,234 --> 00:16:39,080 self should come first always? 360 00:16:39,080 --> 00:16:40,330 BRIAN YU: Yeah, good question. 361 00:16:40,330 --> 00:16:41,390 So does self need to come first? 362 00:16:41,390 --> 00:16:43,820 Yes, self is always going to be the first thing that 363 00:16:43,820 --> 00:16:46,790 is passed into a method for an individual object-- 364 00:16:46,790 --> 00:16:48,840 good question. 365 00:16:48,840 --> 00:16:51,875 OK, so that was a Print Info method. 366 00:16:51,875 --> 00:16:54,500 And the Print Info method didn't take any other arguments other 367 00:16:54,500 --> 00:16:55,130 than just self. 368 00:16:55,130 --> 00:16:58,117 It just required the self to be passed in, 369 00:16:58,117 --> 00:17:00,200 which was just whatever object we're working with. 370 00:17:00,200 --> 00:17:02,090 But we can also allow these custom methods 371 00:17:02,090 --> 00:17:04,470 that we write to take in arguments of their own. 372 00:17:04,470 --> 00:17:06,475 And so we'll take a look at an example of that. 373 00:17:06,475 --> 00:17:10,940 Here in classes3.py, we have the same init method, the same Print Info 374 00:17:10,940 --> 00:17:11,599 method. 375 00:17:11,599 --> 00:17:14,280 But now, let's give the flight the ability to delay itself. 376 00:17:14,280 --> 00:17:17,154 So if the flight's running late and we need the flight to be delayed, 377 00:17:17,154 --> 00:17:20,329 let's give the flight the ability to change its duration by whatever 378 00:17:20,329 --> 00:17:21,589 the delay amount is. 379 00:17:21,589 --> 00:17:25,661 And so here, on line 13, I've defined a new method called Delay, 380 00:17:25,661 --> 00:17:27,910 which takes in the same self as the initial argument-- 381 00:17:27,910 --> 00:17:29,750 what is the object were operating on?-- 382 00:17:29,750 --> 00:17:32,190 and then an amount to delay the flight by. 383 00:17:32,190 --> 00:17:33,830 And so what's happening here-- 384 00:17:33,830 --> 00:17:38,090 inside the Delay function, I've set self.duration plus equals amount 385 00:17:38,090 --> 00:17:41,940 to mean, take whatever duration it was previously and add amount to it. 386 00:17:41,940 --> 00:17:46,750 And so now, inside the main method here, we have-- 387 00:17:46,750 --> 00:17:48,470 f1 is this new flight. 388 00:17:48,470 --> 00:17:52,670 We're going to do f1.delay to say, call the Delay method, 389 00:17:52,670 --> 00:17:55,040 passing in amount as that argument. 390 00:17:55,040 --> 00:17:57,580 So Delay technically takes two arguments-- self and amount. 391 00:17:57,580 --> 00:18:00,452 But remember, self is just implicitly put in there by Python, 392 00:18:00,452 --> 00:18:01,910 so we don't need to worry about it. 393 00:18:01,910 --> 00:18:04,730 Amount is the only one we now need to specify. 394 00:18:04,730 --> 00:18:11,379 So f1.delay(10) is going to say, delay the f1 flight by 10 minutes. 395 00:18:11,379 --> 00:18:13,670 And that is going to update the duration of the flight. 396 00:18:13,670 --> 00:18:16,150 And then we can print the information out after that. 397 00:18:16,150 --> 00:18:20,330 And so, by running Python classes3.py, we now 398 00:18:20,330 --> 00:18:27,800 see that the duration is 550 minutes, as compared to the 540 that we had before. 399 00:18:27,800 --> 00:18:29,882 Questions about any of that so far? 400 00:18:29,882 --> 00:18:32,090 And so one of the nice things-- yeah, quick question? 401 00:18:32,090 --> 00:18:34,779 AUDIENCE: Yes, is main considered a method as well? 402 00:18:34,779 --> 00:18:36,399 Or is it a function? 403 00:18:36,399 --> 00:18:38,190 BRIAN YU: Main is a function, in this case. 404 00:18:38,190 --> 00:18:40,606 It's not a method that's associated with the Flight class. 405 00:18:40,606 --> 00:18:43,991 It just happens to use the flight in it. 406 00:18:43,991 --> 00:18:47,120 And so one of the nice things here is that, inside of main, 407 00:18:47,120 --> 00:18:51,560 I really don't need to worry about exactly how my individual methods are 408 00:18:51,560 --> 00:18:52,460 implemented. 409 00:18:52,460 --> 00:18:55,790 Delay and Print Info might do things that I'm not aware of. 410 00:18:55,790 --> 00:18:58,330 But as long as I understand what the interface is, 411 00:18:58,330 --> 00:19:00,080 that there is a Delay function that allows 412 00:19:00,080 --> 00:19:01,850 me to delay a flight by a certain number of minutes 413 00:19:01,850 --> 00:19:04,940 and a Print Info function that prints out information about a flight, 414 00:19:04,940 --> 00:19:06,410 I just need to know what those are and how 415 00:19:06,410 --> 00:19:08,840 to use them without needing to worry about how they work. 416 00:19:08,840 --> 00:19:11,570 And so, especially on larger projects where multiple people might 417 00:19:11,570 --> 00:19:15,350 be working on different parts of the same program or application, 418 00:19:15,350 --> 00:19:18,440 if one person is writing up the actual implementation of the methods, 419 00:19:18,440 --> 00:19:21,050 someone else can be writing the code that uses those methods, 420 00:19:21,050 --> 00:19:23,480 without needing to worry too much about how exactly 421 00:19:23,480 --> 00:19:27,960 those methods are implemented and what exactly is happening inside of them. 422 00:19:27,960 --> 00:19:32,141 So we've been able to create a Flight class that represents a generic flight. 423 00:19:32,141 --> 00:19:33,890 Let's look at a more sophisticated example 424 00:19:33,890 --> 00:19:36,050 now, where we might have multiple different classes-- where 425 00:19:36,050 --> 00:19:38,716 in addition to having a Flight class, we might also want a class 426 00:19:38,716 --> 00:19:41,141 to represent Passengers, going back to last time 427 00:19:41,141 --> 00:19:43,640 where we were talking about having a separate way of keeping 428 00:19:43,640 --> 00:19:46,770 track of passengers for flights and the flights themselves. 429 00:19:46,770 --> 00:19:51,170 So let's look at classes4.py, which is just going 430 00:19:51,170 --> 00:19:53,880 to be a little more sophisticated. 431 00:19:53,880 --> 00:19:57,920 So the first thing that I'm going to do inside the Flight class now is-- 432 00:19:57,920 --> 00:20:00,950 I'm keeping track of a counter that is going to allow me to number 433 00:20:00,950 --> 00:20:02,210 each one of my flights. 434 00:20:02,210 --> 00:20:05,660 And so this seems similar to that ID column that we had in our SQL 435 00:20:05,660 --> 00:20:09,080 databases last time, where each flight was going to have a different ID. 436 00:20:09,080 --> 00:20:12,320 The reason we're now doing this is that our passengers 437 00:20:12,320 --> 00:20:15,590 need to have some notion of what flight are they associated with. 438 00:20:15,590 --> 00:20:17,740 And an easy way to do that, as we saw last time, 439 00:20:17,740 --> 00:20:20,660 was to associate each passenger with what flight number 440 00:20:20,660 --> 00:20:22,190 that they are tied to. 441 00:20:22,190 --> 00:20:24,159 So this counter is just going to start at 1. 442 00:20:24,159 --> 00:20:27,200 And we're going to update that counter every time we create a new flight. 443 00:20:27,200 --> 00:20:28,550 And we'll see how we do that. 444 00:20:28,550 --> 00:20:31,100 So inside of our init method, we have a couple 445 00:20:31,100 --> 00:20:33,785 of things going on here that are different from last time. 446 00:20:33,785 --> 00:20:35,660 So the first thing that we want to do is keep 447 00:20:35,660 --> 00:20:38,000 track of this particular flight's ID. 448 00:20:38,000 --> 00:20:41,690 So we're going to-- here on line 8-- set the self.ID property 449 00:20:41,690 --> 00:20:43,940 to whatever the Flight.counter is. 450 00:20:43,940 --> 00:20:46,880 Counter was that variable that we created inside of Flight before. 451 00:20:46,880 --> 00:20:49,130 And whatever it is, that's going to be the ID. 452 00:20:49,130 --> 00:20:51,546 And then we're going to take Flight.counter and update it. 453 00:20:51,546 --> 00:20:54,544 Flight.counter plus equals 1, to say, increment the counter 454 00:20:54,544 --> 00:20:55,460 to be the next number. 455 00:20:55,460 --> 00:20:58,130 So that the first flight we create has the ID 1. 456 00:20:58,130 --> 00:21:01,760 Then, Counter updates to 2, so that the next time that I create a new flight, 457 00:21:01,760 --> 00:21:04,530 the ID is going to be 2, and so on and so forth. 458 00:21:04,530 --> 00:21:09,020 Notice that ID is not a parameter that is passed in in the init function. 459 00:21:09,020 --> 00:21:11,750 It's just something that's happening inside of the method 460 00:21:11,750 --> 00:21:14,480 that the user doesn't need to worry about. 461 00:21:14,480 --> 00:21:17,720 We're also going to keep track now of the passengers that 462 00:21:17,720 --> 00:21:19,770 are on this particular flight. 463 00:21:19,770 --> 00:21:22,020 And so we're adding another property, self.passengers, 464 00:21:22,020 --> 00:21:24,395 which is just going to start out equal to the empty list. 465 00:21:24,395 --> 00:21:26,900 We'll maintain a list of all the passengers on this flight. 466 00:21:26,900 --> 00:21:29,733 And it starts out as empty, because when we first create the flight, 467 00:21:29,733 --> 00:21:31,510 nobody is a passenger on that flight. 468 00:21:31,510 --> 00:21:34,760 And then, finally, the last three lines are the same things we've seen before. 469 00:21:34,760 --> 00:21:37,040 We're keeping track of the origin and the destination 470 00:21:37,040 --> 00:21:38,940 and the duration of that flight, in order 471 00:21:38,940 --> 00:21:42,940 to store all that information inside of our Flight object. 472 00:21:42,940 --> 00:21:46,104 So what else do we need to do now? 473 00:21:46,104 --> 00:21:48,270 Print Info looks exactly the same, except we're also 474 00:21:48,270 --> 00:21:49,860 going to print passengers. 475 00:21:49,860 --> 00:21:50,910 And Delay looks the same. 476 00:21:50,910 --> 00:21:55,370 But let's quickly take a look at the Passenger class on line 37. 477 00:21:55,370 --> 00:21:57,420 So the Passenger class is actually very simple. 478 00:21:57,420 --> 00:21:59,610 All the Passenger class is doing right now 479 00:21:59,610 --> 00:22:02,020 is it's keeping track of its own name. 480 00:22:02,020 --> 00:22:04,020 So when we create a new passenger, we're setting 481 00:22:04,020 --> 00:22:06,750 self.name equal to whatever the name of the passenger is. 482 00:22:06,750 --> 00:22:08,790 And now, we've created a new passenger. 483 00:22:08,790 --> 00:22:15,570 And so how then do we keep track or tie passengers together 484 00:22:15,570 --> 00:22:18,060 with an individual flight? 485 00:22:18,060 --> 00:22:23,010 Well, that's happening here inside of this Add Passenger method. 486 00:22:23,010 --> 00:22:27,270 And so the Add Passenger method takes this input, self, which is the flight. 487 00:22:27,270 --> 00:22:33,356 Notice that Add Passenger is a method of the Flight class. 488 00:22:33,356 --> 00:22:35,640 And so what is Add Passenger doing? 489 00:22:35,640 --> 00:22:37,230 It takes, as input, itself. 490 00:22:37,230 --> 00:22:41,307 And it takes, as input, p, which is just going to be a Passenger object. 491 00:22:41,307 --> 00:22:43,140 And here are the two things that we're going 492 00:22:43,140 --> 00:22:45,556 to do to keep track of these relationships between flights 493 00:22:45,556 --> 00:22:46,450 and passengers. 494 00:22:46,450 --> 00:22:48,450 The first thing we're going to do is take 495 00:22:48,450 --> 00:22:54,325 self.passengers which, you'll recall from up here, begins as an empty list. 496 00:22:54,325 --> 00:22:56,980 self.passengers begins as an empty list. 497 00:22:56,980 --> 00:22:59,700 And what we're going to do is append to that list. 498 00:22:59,700 --> 00:23:01,620 All lists in Python have an Append method 499 00:23:01,620 --> 00:23:03,600 that adds another thing to the list. 500 00:23:03,600 --> 00:23:06,060 And we're just going to add the passenger, p, 501 00:23:06,060 --> 00:23:07,656 to our list of passengers. 502 00:23:07,656 --> 00:23:10,530 So now, our flight, which is keeping track of our list of passengers, 503 00:23:10,530 --> 00:23:13,560 now knows that there's another passenger on this flight. 504 00:23:13,560 --> 00:23:18,180 And now, on this next line, we're setting the passenger's flight ID 505 00:23:18,180 --> 00:23:21,770 to be equal to whatever self.id is. 506 00:23:21,770 --> 00:23:24,090 So now, the passenger knows, via that flight ID 507 00:23:24,090 --> 00:23:26,610 property, what the ID of the flight is. 508 00:23:26,610 --> 00:23:29,700 Remember, self is the Flight object. 509 00:23:29,700 --> 00:23:31,860 P is the Passenger object. 510 00:23:31,860 --> 00:23:36,120 So we add to the flight's list of passengers that new Passenger object. 511 00:23:36,120 --> 00:23:39,880 And then we update the Passenger object to keep track of what flight 512 00:23:39,880 --> 00:23:42,241 it is associated with. 513 00:23:42,241 --> 00:23:45,240 And Print Info now, in addition to printing out the origin, destination, 514 00:23:45,240 --> 00:23:48,330 and duration of the flight, will also run a loop, 515 00:23:48,330 --> 00:23:51,150 looping over all of self.passengers, looping 516 00:23:51,150 --> 00:23:53,770 over every passenger in that list of passengers, 517 00:23:53,770 --> 00:23:57,754 and printing out that passenger's name. 518 00:23:57,754 --> 00:23:58,670 So how do we use that? 519 00:23:58,670 --> 00:24:00,070 What does that look like? 520 00:24:00,070 --> 00:24:02,940 Well, inside of our Main function here, we first 521 00:24:02,940 --> 00:24:05,669 create a flight, f1, same as before. 522 00:24:05,669 --> 00:24:07,710 And now we're going to create Passenger objects-- 523 00:24:07,710 --> 00:24:08,806 Alice and Bob. 524 00:24:08,806 --> 00:24:10,680 We just create them using the Passenger class 525 00:24:10,680 --> 00:24:13,070 and providing a name for what their name is. 526 00:24:13,070 --> 00:24:15,480 And now, in order to add passengers, we just 527 00:24:15,480 --> 00:24:17,980 need to call this Add Passenger method on the flight. 528 00:24:17,980 --> 00:24:19,290 So f1 is our flight. 529 00:24:19,290 --> 00:24:20,910 Add Passenger is the method. 530 00:24:20,910 --> 00:24:23,280 Alice is the name of a passenger object. 531 00:24:23,280 --> 00:24:25,680 And so each time we call Add Passenger, that 532 00:24:25,680 --> 00:24:28,950 is going to append to the list of f1's passengers 533 00:24:28,950 --> 00:24:32,160 and also update Alice's flight ID property to be 534 00:24:32,160 --> 00:24:35,430 equal to whatever the ID of f1 is. 535 00:24:35,430 --> 00:24:38,820 And so, when we Print Info at the end here, after adding two passengers, 536 00:24:38,820 --> 00:24:43,650 the result is that we get the information about the flight and then, 537 00:24:43,650 --> 00:24:49,120 also, the list of the names of the two passengers that we have on that flight. 538 00:24:49,120 --> 00:24:52,020 And so was two different classes now interacting together 539 00:24:52,020 --> 00:24:53,310 in a way that's meaningful. 540 00:24:53,310 --> 00:24:56,995 Questions about any of that and how that worked? 541 00:24:56,995 --> 00:24:57,495 Yeah? 542 00:24:57,495 --> 00:25:01,375 AUDIENCE: So when I have [INAUDIBLE] passengers in the flight, 543 00:25:01,375 --> 00:25:05,740 if I want to [INAUDIBLE] this particular passenger in the flight, 544 00:25:05,740 --> 00:25:07,190 how would I search him? 545 00:25:07,190 --> 00:25:08,190 BRIAN YU: Good question. 546 00:25:08,190 --> 00:25:11,400 So the question is, well, OK, I'm maintaining this list of passengers. 547 00:25:11,400 --> 00:25:13,890 What if I wanted to search through the passengers? 548 00:25:13,890 --> 00:25:16,340 Find a passenger named Alice, for example, 549 00:25:16,340 --> 00:25:19,050 in a list of a dozen or more passengers? 550 00:25:19,050 --> 00:25:22,450 So certainly, you could write Python code that would be able to do that. 551 00:25:22,450 --> 00:25:25,320 That could, for instance, loop through your list of passengers 552 00:25:25,320 --> 00:25:26,310 in order to find it. 553 00:25:26,310 --> 00:25:29,970 But ultimately, this is starting to be the type of situation 554 00:25:29,970 --> 00:25:33,060 where we would really like to be able to use a database. 555 00:25:33,060 --> 00:25:37,950 Because a database, like a SQL database, lets us perform queries like Select* 556 00:25:37,950 --> 00:25:40,560 from passengers where Name equals Alice, for instance, 557 00:25:40,560 --> 00:25:44,730 that lets us get at just Alice's passenger information. 558 00:25:44,730 --> 00:25:47,430 And so far, what we've been doing has been 559 00:25:47,430 --> 00:25:49,859 a lot of just writing Python code that doesn't actually 560 00:25:49,859 --> 00:25:51,150 interact with any database yet. 561 00:25:51,150 --> 00:25:53,190 We haven't tied this to a SQL database. 562 00:25:53,190 --> 00:25:54,510 But that's where we're headed. 563 00:25:54,510 --> 00:25:59,970 And so in fact, what we're going to talk about next is going to be something 564 00:25:59,970 --> 00:26:01,950 called object relational mapping. 565 00:26:01,950 --> 00:26:04,980 And so the idea of Object Relational Mapping, or ORM, 566 00:26:04,980 --> 00:26:08,460 is that we have this powerful language feature in Python, 567 00:26:08,460 --> 00:26:10,710 this object-oriented programming syntax that 568 00:26:10,710 --> 00:26:13,530 lets us create classes, like the Flight class, 569 00:26:13,530 --> 00:26:16,880 define properties on those classes, like the destination and duration; 570 00:26:16,880 --> 00:26:19,530 lets us define methods on those classes that 571 00:26:19,530 --> 00:26:21,920 let us add behavior or functionality to those classes-- 572 00:26:21,920 --> 00:26:25,350 the ability to add a passenger or the ability to delay a flight. 573 00:26:25,350 --> 00:26:27,630 And we also have-- in sort of a separate world-- 574 00:26:27,630 --> 00:26:31,050 our world of SQL databases-- or database of tables, each one of which 575 00:26:31,050 --> 00:26:35,550 has some number of rows to which we can insert, or update, or select, or delete 576 00:26:35,550 --> 00:26:36,300 from them. 577 00:26:36,300 --> 00:26:39,000 And what object-relational mapping is going to allow us to do 578 00:26:39,000 --> 00:26:40,800 is tie those two worlds together. 579 00:26:40,800 --> 00:26:43,470 Its going to allow us to use Python classes and methods 580 00:26:43,470 --> 00:26:46,569 and objects to interact with a SQL database. 581 00:26:46,569 --> 00:26:48,360 And so that's ultimately where we're headed 582 00:26:48,360 --> 00:26:52,290 and what we're going to look at a couple of examples of in just a moment. 583 00:26:52,290 --> 00:26:54,000 And in order to do that-- 584 00:26:54,000 --> 00:26:56,190 tie it with web applications written in Flask-- 585 00:26:56,190 --> 00:27:00,210 we're going to use a package called Flask SQLAlchemy, which 586 00:27:00,210 --> 00:27:04,230 is a way of tying SQLAlchemy, which we were using last time in order 587 00:27:04,230 --> 00:27:08,100 to write Python code that allowed us to execute database statements. 588 00:27:08,100 --> 00:27:11,190 And it's going to make it easier to tie that in with a Flask application, 589 00:27:11,190 --> 00:27:15,390 so it's such that, when users are using our Flask application, 590 00:27:15,390 --> 00:27:18,389 they can take advantage of more database features. 591 00:27:18,389 --> 00:27:21,680 And we'll take a look at examples of how that's going to work in just a moment. 592 00:27:21,680 --> 00:27:24,330 But the end goal here is to be able to use 593 00:27:24,330 --> 00:27:27,870 Python code and classes and object-oriented programming 594 00:27:27,870 --> 00:27:30,550 to be able to interact with our databases. 595 00:27:30,550 --> 00:27:34,530 So let's take a look at how we might go about doing that in SQLAlchemy 596 00:27:34,530 --> 00:27:36,000 with Flask. 597 00:27:36,000 --> 00:27:39,750 So let's take a look at models.py here, which 598 00:27:39,750 --> 00:27:43,200 is going to be a key file for understanding how we're 599 00:27:43,200 --> 00:27:45,220 going to tie these two worlds together. 600 00:27:45,220 --> 00:27:49,260 And so this is a file written using this Flask SQLAlchemy framework. 601 00:27:49,260 --> 00:27:52,745 And what we're doing here is we're going to define classes. 602 00:27:52,745 --> 00:27:54,870 And the relationship that we're going to understand 603 00:27:54,870 --> 00:27:58,170 is that, for any table that we want inside of our database, 604 00:27:58,170 --> 00:28:02,130 we're going to have one class inside of this Models file. 605 00:28:02,130 --> 00:28:05,350 And so the key lines to take a look at here are 5 through 10, 606 00:28:05,350 --> 00:28:08,250 where we're defining this Flight class. 607 00:28:08,250 --> 00:28:10,980 We added this db.model here in parentheses 608 00:28:10,980 --> 00:28:15,380 to mean that the flight is inheriting from the DB.model 609 00:28:15,380 --> 00:28:17,785 or the model of the SQLAlchemy database. 610 00:28:17,785 --> 00:28:20,160 No need to worry too much about what exactly that means-- 611 00:28:20,160 --> 00:28:22,650 but effectively, we're allowing our Flight class 612 00:28:22,650 --> 00:28:26,650 to be defined as a class that has some built in relationship that SQLAlchemy 613 00:28:26,650 --> 00:28:29,530 has written for interacting with our database. 614 00:28:29,530 --> 00:28:31,890 And so, what does this class, Flight, look like? 615 00:28:31,890 --> 00:28:37,230 Well, in line 6, where you define this first property, __tablename__-- 616 00:28:37,230 --> 00:28:40,476 this is going to correspond with the name of the table 617 00:28:40,476 --> 00:28:42,100 that we want to create in our database. 618 00:28:42,100 --> 00:28:44,190 So recall that, inside of our SQL database, 619 00:28:44,190 --> 00:28:46,410 every database has a number of tables. 620 00:28:46,410 --> 00:28:48,340 And every table has a name. 621 00:28:48,340 --> 00:28:52,050 This is saying that the class, Flight, should correspond with the table 622 00:28:52,050 --> 00:28:54,300 name, flights-- all lowercase. 623 00:28:54,300 --> 00:28:55,680 And now, after that-- 624 00:28:55,680 --> 00:28:57,370 one on each row-- 625 00:28:57,370 --> 00:29:02,790 we're going to define the columns that are contained inside of our Flight 626 00:29:02,790 --> 00:29:05,060 table, much like we did before. 627 00:29:05,060 --> 00:29:07,370 So each flight is going to have an ID. 628 00:29:07,370 --> 00:29:09,300 And so, ID is a column. 629 00:29:09,300 --> 00:29:10,170 And what type is it? 630 00:29:10,170 --> 00:29:11,800 Well, it's an integer. 631 00:29:11,800 --> 00:29:13,590 And it's going to be, primary key is true. 632 00:29:13,590 --> 00:29:18,900 So it's going to be the primary way via which we identify a Flight object. 633 00:29:18,900 --> 00:29:21,510 And likewise, we have origin, which is going 634 00:29:21,510 --> 00:29:24,750 to be a column that is a string value. 635 00:29:24,750 --> 00:29:29,280 And nullable=false is the equivalent of what we did in SQL to say, no, 636 00:29:29,280 --> 00:29:31,950 we don't want a flight to have no origin. 637 00:29:31,950 --> 00:29:33,960 And same for destination. 638 00:29:33,960 --> 00:29:36,540 That is likewise going to be a string that is not nullable. 639 00:29:36,540 --> 00:29:38,490 And the duration is going to be the amount of time, 640 00:29:38,490 --> 00:29:39,906 in minutes, that the flight lasts. 641 00:29:39,906 --> 00:29:41,340 That's going to be an integer. 642 00:29:41,340 --> 00:29:44,670 And so what we've done here is defined a Python class 643 00:29:44,670 --> 00:29:49,230 that has all of these properties that represent the individual columns. 644 00:29:49,230 --> 00:29:52,200 And that's going to allow us to use Flight objects, 645 00:29:52,200 --> 00:29:54,690 like the ones we were using in the examples a moment ago, 646 00:29:54,690 --> 00:30:00,360 to actually interact with the database, such that when we say, f1.duration+=10, 647 00:30:00,360 --> 00:30:03,850 because they update the duration-- that is actually going to, automatically-- 648 00:30:03,850 --> 00:30:05,250 through SQLAlchemy-- 649 00:30:05,250 --> 00:30:09,950 perform an update on our database to update the duration of that flight 650 00:30:09,950 --> 00:30:12,140 to be 10 minutes longer. 651 00:30:12,140 --> 00:30:17,720 And so, likewise, we're doing the same thing here in the Passenger class, 652 00:30:17,720 --> 00:30:19,700 where we defined a class called Passenger. 653 00:30:19,700 --> 00:30:23,600 And the table name for that is going to be Passengers. 654 00:30:23,600 --> 00:30:26,090 Each passenger has an ID, which is an integer. 655 00:30:26,090 --> 00:30:28,400 Each passenger has a name, which is a string. 656 00:30:28,400 --> 00:30:29,531 And then, flight ID-- 657 00:30:29,531 --> 00:30:31,280 if we recall, flight ID is what we've call 658 00:30:31,280 --> 00:30:35,780 a foreign key, a column of our table that was referencing 659 00:30:35,780 --> 00:30:37,400 some column of some other table. 660 00:30:37,400 --> 00:30:40,790 In particular, the flight ID column of our Passengers table 661 00:30:40,790 --> 00:30:44,180 was going to reference the ID column of our Flights table. 662 00:30:44,180 --> 00:30:47,480 That way, for any given passenger, you can associate them with which flight 663 00:30:47,480 --> 00:30:49,010 that they are a part of. 664 00:30:49,010 --> 00:30:51,500 And so flight ID is also going to be a column. 665 00:30:51,500 --> 00:30:53,270 It's going to be of type integer. 666 00:30:53,270 --> 00:30:57,230 And it's going to be a foreign key, we can additionally specify. 667 00:30:57,230 --> 00:30:59,540 And what column is it going to reference? 668 00:30:59,540 --> 00:31:03,800 Well, it's going to reference the flights.ID column-- in particular, 669 00:31:03,800 --> 00:31:06,950 the ID column of our Flights table. 670 00:31:06,950 --> 00:31:10,550 And so, so far, this hasn't yet added any functionality for us. 671 00:31:10,550 --> 00:31:16,370 But you can see that we've rewritten the existing syntax of the Create Table 672 00:31:16,370 --> 00:31:21,020 commands that you've likely been using in order to create tables in SQL. 673 00:31:21,020 --> 00:31:24,680 And we've rewritten that, using Python classes, such that, in a moment, 674 00:31:24,680 --> 00:31:26,690 we'll be able to actually interact with them, 675 00:31:26,690 --> 00:31:30,690 in order to do some interesting or useful work. 676 00:31:30,690 --> 00:31:35,480 So let's take a look now at how we might actually use that. 677 00:31:35,480 --> 00:31:42,020 And so, one immediately nice feature is that, when we have a class like this-- 678 00:31:42,020 --> 00:31:45,140 this is just the same thing that we saw in models.py just a moment ago-- 679 00:31:45,140 --> 00:31:48,810 it makes it very easy for us, now, to be able to create those tables. 680 00:31:48,810 --> 00:31:52,220 So before, when in SQL you wanted to create a new table, 681 00:31:52,220 --> 00:31:56,000 you would either-- via the command line or by using a web interface, like admin 682 00:31:56,000 --> 00:31:59,960 or-- you would type in a Create Table command that 683 00:31:59,960 --> 00:32:03,090 would create a table, Flights, that has all of these columns. 684 00:32:03,090 --> 00:32:05,720 Well, if you define a class like this, SQLAlchemy already 685 00:32:05,720 --> 00:32:08,970 knows how to take this and translate it into SQL syntax. 686 00:32:08,970 --> 00:32:12,014 So instead of needing to write code, like, Create Table flights, 687 00:32:12,014 --> 00:32:14,180 with all of these columns, like we saw before-- this 688 00:32:14,180 --> 00:32:17,420 is how we would conventionally just create a table using raw SQL. 689 00:32:17,420 --> 00:32:21,410 SQLAlchemy lets us do a command, like, db.create_all that will take 690 00:32:21,410 --> 00:32:24,350 our classes and just automatically create all of those tables, 691 00:32:24,350 --> 00:32:29,480 using the types that we specified, using those nullable=false constraints 692 00:32:29,480 --> 00:32:32,780 to say, don't allow this particular column to be null. 693 00:32:32,780 --> 00:32:35,840 And so this vastly simplifies the process of creating a table, 694 00:32:35,840 --> 00:32:38,120 without needing to worry about the exact SQL syntax. 695 00:32:38,120 --> 00:32:41,374 We can just use our Python classes instead. 696 00:32:41,374 --> 00:32:43,790 And so let's take a look at how we would actually do that, 697 00:32:43,790 --> 00:32:46,880 using Flask SQLAlchemy. 698 00:32:46,880 --> 00:32:52,980 So inside of create.py, we have, up here, a little bit of configuration. 699 00:32:52,980 --> 00:32:57,470 This configuration is just telling our Flask application what database to use. 700 00:32:57,470 --> 00:33:00,170 Here, we're drawing from the environment variable database URL, 701 00:33:00,170 --> 00:33:02,930 much like you saw in some of the examples and in project 1, 702 00:33:02,930 --> 00:33:04,010 for instance. 703 00:33:04,010 --> 00:33:11,030 And I also am going to import from Models 704 00:33:11,030 --> 00:33:14,010 that file that we had earlier that defined all of the various classes-- 705 00:33:14,010 --> 00:33:16,040 import*, to mean, import everything. 706 00:33:16,040 --> 00:33:17,210 Import all of those classes. 707 00:33:17,210 --> 00:33:18,680 And import that database. 708 00:33:18,680 --> 00:33:24,200 And this db.init_app(app) is saying, tie this database with this Flask 709 00:33:24,200 --> 00:33:24,741 application. 710 00:33:24,741 --> 00:33:26,990 So we're not actually running a Flask application yet. 711 00:33:26,990 --> 00:33:29,823 But we're going to use Flask SQLAlchemy and build up to, eventually, 712 00:33:29,823 --> 00:33:32,540 using a web application using these features. 713 00:33:32,540 --> 00:33:36,990 And so now, inside of our main function, all we need to do is say, 714 00:33:36,990 --> 00:33:38,540 db.create_all. 715 00:33:38,540 --> 00:33:41,750 And that's going to create tables, based on what 716 00:33:41,750 --> 00:33:46,890 we had inside of our Models file and all of those classes that we defined there. 717 00:33:46,890 --> 00:33:51,270 And if you're curious, down here in the "if name equals main," this here, 718 00:33:51,270 --> 00:33:56,030 the with app.app_context is just one of the nuances of Flask, 719 00:33:56,030 --> 00:33:59,896 which is that Flask has particular rules for when you're allowed to interact 720 00:33:59,896 --> 00:34:00,770 with the application. 721 00:34:00,770 --> 00:34:03,860 In particular, Flask behaves slightly differently 722 00:34:03,860 --> 00:34:07,610 when a user is requesting to access a Flask web-page versus when 723 00:34:07,610 --> 00:34:09,860 there is no request to the application. 724 00:34:09,860 --> 00:34:15,320 And we need this with app.app_context to allow us to, on the command line, 725 00:34:15,320 --> 00:34:16,820 interact with our Flask application. 726 00:34:16,820 --> 00:34:20,929 Because our command line program needs to have some notion of what 727 00:34:20,929 --> 00:34:22,783 Flask application we're dealing with. 728 00:34:22,783 --> 00:34:24,449 So no need to worry about that too much. 729 00:34:24,449 --> 00:34:27,199 But just wanted to give you some context for what that line is, in case you 730 00:34:27,199 --> 00:34:29,010 see it in a couple of the files here. 731 00:34:29,010 --> 00:34:33,374 So what I'm going to do now is open up the lecture 4 database. 732 00:34:33,374 --> 00:34:35,040 And I'm doing this via the command line. 733 00:34:35,040 --> 00:34:36,230 But again, you could look at the same thing 734 00:34:36,230 --> 00:34:38,780 using Admin or any of the other web-based tools 735 00:34:38,780 --> 00:34:40,639 for taking a look at web sites. 736 00:34:40,639 --> 00:34:45,889 And in a post square syntax, backslash d lists out all of the tables 737 00:34:45,889 --> 00:34:47,090 that I currently have. 738 00:34:47,090 --> 00:34:50,130 And right now, we find no relations-- no tables, effectively. 739 00:34:50,130 --> 00:34:55,460 And so, if I now run my create.py code, remembering that all I did inside 740 00:34:55,460 --> 00:35:02,000 of create.py was run this db.create_all line inside of my main function-- 741 00:35:02,000 --> 00:35:05,570 once that's done, if I go back here and do backslash d, 742 00:35:05,570 --> 00:35:09,410 now I have a Flights table and this Passengers table. 743 00:35:09,410 --> 00:35:10,950 Those tables were created for me. 744 00:35:10,950 --> 00:35:13,250 I didn't need to run the Create Table command in order 745 00:35:13,250 --> 00:35:14,300 to allow that to happen. 746 00:35:14,300 --> 00:35:17,050 And so that's one compelling feature right out-of-the-box of Flask 747 00:35:17,050 --> 00:35:19,460 SQLAlchemy, which is that it lets us, very easily, 748 00:35:19,460 --> 00:35:23,270 create tables just using Python code and without needing to worry about 749 00:35:23,270 --> 00:35:25,490 the specific syntax in SQL. 750 00:35:25,490 --> 00:35:27,620 But let's take a look now at other things 751 00:35:27,620 --> 00:35:29,435 that we might reasonably want to do. 752 00:35:29,435 --> 00:35:31,310 I'll take a look at it at a high level first. 753 00:35:31,310 --> 00:35:33,900 And then we'll dive into some more concrete examples. 754 00:35:33,900 --> 00:35:37,670 So let's say that we wanted to do something 755 00:35:37,670 --> 00:35:41,750 like inserting into the Flights table. 756 00:35:41,750 --> 00:35:45,170 And so we might reasonably have, in SQL, a line that 757 00:35:45,170 --> 00:35:48,020 would look something like this-- insert into flights in origin, 758 00:35:48,020 --> 00:35:49,640 destination, and duration. 759 00:35:49,640 --> 00:35:50,234 What values? 760 00:35:50,234 --> 00:35:51,650 Well, the origin will be New York. 761 00:35:51,650 --> 00:35:52,691 The destination is Paris. 762 00:35:52,691 --> 00:35:54,230 The duration of 540. 763 00:35:54,230 --> 00:35:56,960 That was what we've seen before, just in the world of SQL. 764 00:35:56,960 --> 00:35:59,567 Now, how would we translate that to use our Python classes 765 00:35:59,567 --> 00:36:00,900 to be able to do the same thing? 766 00:36:00,900 --> 00:36:04,280 What would the Python code for that look like, using SQLAlchemy? 767 00:36:04,280 --> 00:36:06,290 Well, it might look something like this. 768 00:36:06,290 --> 00:36:09,260 These first three lines are just what we've already done before. 769 00:36:09,260 --> 00:36:13,250 Flight is equal to a new Flight object, using this Flight class. 770 00:36:13,250 --> 00:36:15,825 We're specifying the origin, destination, and duration. 771 00:36:15,825 --> 00:36:17,200 We saw this in the code examples. 772 00:36:17,200 --> 00:36:18,116 This is just one line. 773 00:36:18,116 --> 00:36:21,290 But I've broken it up on the multiple, just for space reasons. 774 00:36:21,290 --> 00:36:23,720 And then after we've created that Flight object, 775 00:36:23,720 --> 00:36:26,270 I want to add it to my database. 776 00:36:26,270 --> 00:36:31,280 And so I'll use a line like db.session.add(flight). 777 00:36:31,280 --> 00:36:33,590 Recall from last time that we talked about 778 00:36:33,590 --> 00:36:36,770 how, if we wanted to group a bunch of commands together, 779 00:36:36,770 --> 00:36:39,980 we might use sessions that we commit at the end of every session to group 780 00:36:39,980 --> 00:36:41,270 a bunch of commands together. 781 00:36:41,270 --> 00:36:45,540 Flask SQLAlchemy does that for us and just automatically will create these 782 00:36:45,540 --> 00:36:49,750 sessions for us, so that we can say, db.session.add(flight) to mean, 783 00:36:49,750 --> 00:36:52,730 add this flight object to my database. 784 00:36:52,730 --> 00:36:58,065 And so this would be the Python Flask SQLAlchemy version of the same SQL code 785 00:36:58,065 --> 00:36:58,940 that we wrote before. 786 00:36:58,940 --> 00:37:02,630 We create the object, just the same way we would create any Python object. 787 00:37:02,630 --> 00:37:05,560 And then we add it to our database. 788 00:37:05,560 --> 00:37:07,840 And so that would be the equivalent of the insert. 789 00:37:07,840 --> 00:37:08,870 What about select? 790 00:37:08,870 --> 00:37:10,460 Select star from flights-- 791 00:37:10,460 --> 00:37:13,340 well, now that we have this Flight class, 792 00:37:13,340 --> 00:37:16,280 we can use any of the features that have been added to this class. 793 00:37:16,280 --> 00:37:18,740 So recall that, in the flight examples that we 794 00:37:18,740 --> 00:37:22,880 saw before, we added a special function called 795 00:37:22,880 --> 00:37:24,410 Delay that would delay our flight. 796 00:37:24,410 --> 00:37:29,380 We added a function called Add Passenger that added a passenger to our flight. 797 00:37:29,380 --> 00:37:31,970 SQLAlchemy does this for us by adding a property 798 00:37:31,970 --> 00:37:35,960 to our flights called Query that lets us query for particular information 799 00:37:35,960 --> 00:37:37,000 about our flights. 800 00:37:37,000 --> 00:37:41,090 And in particular, syntax like Flight.query.all 801 00:37:41,090 --> 00:37:43,490 is going to be a method that will do exactly this, just 802 00:37:43,490 --> 00:37:46,690 query for all of the flight information and give it back to us. 803 00:37:46,690 --> 00:37:49,190 And again, we'll take a look at a couple of examples of what 804 00:37:49,190 --> 00:37:50,960 that looks like in just a moment. 805 00:37:50,960 --> 00:37:53,390 But I wanted to show you a couple other ones. 806 00:37:53,390 --> 00:37:55,850 So what about if we only wanted to select 807 00:37:55,850 --> 00:37:58,130 from flights where the origin is Paris? 808 00:37:58,130 --> 00:38:02,000 So we use this Where clause to filter out only particular flights 809 00:38:02,000 --> 00:38:02,990 that we care about. 810 00:38:02,990 --> 00:38:05,090 Well, that would look something like this. 811 00:38:05,090 --> 00:38:07,230 Flight.query is the same as before. 812 00:38:07,230 --> 00:38:07,730 And 813 00:38:07,730 --> 00:38:12,050 Then this filter_by lets us add additional information to this query. 814 00:38:12,050 --> 00:38:14,960 In particular, I want to filter my flight query, 815 00:38:14,960 --> 00:38:16,949 only where origin is equal to Paris. 816 00:38:16,949 --> 00:38:18,740 And then .all, again, is just going to say, 817 00:38:18,740 --> 00:38:23,700 select all of the flights that match origin equal to Paris. 818 00:38:23,700 --> 00:38:27,620 And so let's take a look at some of that, in actual code, 819 00:38:27,620 --> 00:38:30,350 to take a look at how we might actually use that. 820 00:38:30,350 --> 00:38:37,590 So let's first take a look at importing information into our database. 821 00:38:37,590 --> 00:38:39,840 So this is import0.py. 822 00:38:39,840 --> 00:38:41,970 This is what we saw last time, in fact. 823 00:38:41,970 --> 00:38:44,060 This is a repeat of the code that we saw before, 824 00:38:44,060 --> 00:38:48,170 where we had a line like db.execute, insert into flights origin, 825 00:38:48,170 --> 00:38:49,610 destination, duration-- 826 00:38:49,610 --> 00:38:51,680 these particular values, where we were explicitly 827 00:38:51,680 --> 00:38:56,790 writing SQL syntax into our Python code to mean, execute this SQL syntax. 828 00:38:56,790 --> 00:38:58,580 What we're going to be looking at today is 829 00:38:58,580 --> 00:39:03,110 how we can use Python classes and objects and this technology of ORM 830 00:39:03,110 --> 00:39:05,960 to be able to avoid needing to write explicit SQL syntax 831 00:39:05,960 --> 00:39:08,000 inside of our Python files. 832 00:39:08,000 --> 00:39:10,700 And we can just use these classes and objects 833 00:39:10,700 --> 00:39:13,190 to be able to achieve the same effects. 834 00:39:13,190 --> 00:39:16,700 So let's take a look at import1, which is our new version of the same thing. 835 00:39:16,700 --> 00:39:19,760 The configuration up here at the top is the same as we saw before. 836 00:39:19,760 --> 00:39:22,290 But the interesting stuff is happening here. 837 00:39:22,290 --> 00:39:25,340 So after we open our CSV file, we're going 838 00:39:25,340 --> 00:39:29,090 to run a for loop that is going to loop over every line in the CSV file, 839 00:39:29,090 --> 00:39:30,260 just like before. 840 00:39:30,260 --> 00:39:32,510 But instead of running an insert into query 841 00:39:32,510 --> 00:39:36,800 explicitly by reading db.execute insert into the flight's table, 842 00:39:36,800 --> 00:39:39,665 we're just going to create a new flight, which 843 00:39:39,665 --> 00:39:42,290 is going to be a Flight object that has an origin, destination, 844 00:39:42,290 --> 00:39:45,470 and duration, just like we saw when we were creating objects 845 00:39:45,470 --> 00:39:47,630 from classes before. 846 00:39:47,630 --> 00:39:51,452 We're going to say db.session.add(flight) to mean add this 847 00:39:51,452 --> 00:39:52,410 flight to our database. 848 00:39:52,410 --> 00:39:54,980 This is the equivalent of running that Insert command. 849 00:39:54,980 --> 00:39:57,500 And then at the end db.session.commit says, 850 00:39:57,500 --> 00:39:59,104 we've made changes to the database. 851 00:39:59,104 --> 00:40:01,520 I need to tell the database, yes, I'm done making changes. 852 00:40:01,520 --> 00:40:04,820 Now, go ahead and actually make those changes, same as before. 853 00:40:04,820 --> 00:40:09,980 And so db.session.commit says, go ahead and actually make those changes. 854 00:40:09,980 --> 00:40:14,710 So now, if I run the import1.py, it's going 855 00:40:14,710 --> 00:40:16,980 to say that we've added all those flights. 856 00:40:16,980 --> 00:40:19,430 And so, now how do I look at them? 857 00:40:19,430 --> 00:40:20,780 How do I select from them? 858 00:40:20,780 --> 00:40:23,510 Let's take a look at some of those Select queries as well. 859 00:40:23,510 --> 00:40:26,840 And so, let's look at list0.py. 860 00:40:26,840 --> 00:40:28,720 And so I had list0.py. 861 00:40:28,720 --> 00:40:30,740 This is, again, the same thing as we saw before. 862 00:40:30,740 --> 00:40:35,260 We have db.execute select origin, destination, and duration from flights. 863 00:40:35,260 --> 00:40:39,010 This was the explicit SQL syntax for selecting information out 864 00:40:39,010 --> 00:40:40,210 of our tables. 865 00:40:40,210 --> 00:40:42,400 And so after we selected that information, 866 00:40:42,400 --> 00:40:46,330 we looped over our list of flights and just printed out information 867 00:40:46,330 --> 00:40:47,930 about each one. 868 00:40:47,930 --> 00:40:51,064 But now, inside of list1.py inside our main function, 869 00:40:51,064 --> 00:40:52,730 we'll do something slightly differently. 870 00:40:52,730 --> 00:40:56,680 Instead of explicitly using that select star from flights syntax, 871 00:40:56,680 --> 00:41:02,112 we'll use flights=Flights.query.all to mean, select all of the flights. 872 00:41:02,112 --> 00:41:04,070 And now, we're just going to do the same thing. 873 00:41:04,070 --> 00:41:05,030 These little two lines are the same. 874 00:41:05,030 --> 00:41:06,482 We're looping over each flight. 875 00:41:06,482 --> 00:41:08,440 And for each individual flight, we're print out 876 00:41:08,440 --> 00:41:11,760 its origin, destination, and duration. 877 00:41:11,760 --> 00:41:16,210 And so now, by running Python list1.py, we've 878 00:41:16,210 --> 00:41:18,940 listed out information about all of those flights. 879 00:41:18,940 --> 00:41:22,030 And so we're slowly starting to translate the language of pure SQL 880 00:41:22,030 --> 00:41:26,020 to using Python classes and methods to be able to perform the same thing. 881 00:41:26,020 --> 00:41:29,430 And we'll see, soon, how that can become very powerful, as our SQL syntax might 882 00:41:29,430 --> 00:41:33,340 to get more complicated but our Python code can remain relatively simple. 883 00:41:33,340 --> 00:41:35,670 Questions about any of this so far? 884 00:41:35,670 --> 00:41:36,170 Yeah? 885 00:41:36,170 --> 00:41:37,795 AUDIENCE: Is Flights in the dictionary? 886 00:41:37,795 --> 00:41:38,710 Or it's a list? 887 00:41:38,710 --> 00:41:39,709 BRIAN YU: Good question. 888 00:41:39,709 --> 00:41:41,200 What is the type of this Flights? 889 00:41:41,200 --> 00:41:43,180 Flights here is going to be a list, where 890 00:41:43,180 --> 00:41:47,890 each individual element of that list is going to be an individual flight. 891 00:41:47,890 --> 00:41:50,530 And that is of the type Flight, that class that we've created. 892 00:41:50,530 --> 00:41:53,830 And you can access the properties of those individual flights 893 00:41:53,830 --> 00:41:55,780 by origin, destination, and duration. 894 00:41:55,780 --> 00:41:58,690 And so you can see, if I were to print Flights here and just 895 00:41:58,690 --> 00:42:03,170 print out what the value of that is and run list1 again, 896 00:42:03,170 --> 00:42:06,220 you'll see that what I have here is what Flight 897 00:42:06,220 --> 00:42:09,880 is, which is just a list of all of those individual flights, 898 00:42:09,880 --> 00:42:13,270 where each one is one of these individual flight objects 899 00:42:13,270 --> 00:42:16,390 that I've created from my models. 900 00:42:16,390 --> 00:42:17,290 Good question though. 901 00:42:17,290 --> 00:42:20,860 Yeah-- so .all gives me back a list of all of the objects that successfully 902 00:42:20,860 --> 00:42:22,450 returned from that query. 903 00:42:22,450 --> 00:42:25,420 904 00:42:25,420 --> 00:42:28,450 Other things? 905 00:42:28,450 --> 00:42:31,910 OK, let's take a look at a little more of the syntax 906 00:42:31,910 --> 00:42:34,907 of how we might do things. 907 00:42:34,907 --> 00:42:37,490 One common thing that we want to do is select from a database, 908 00:42:37,490 --> 00:42:41,030 but only select one thing, only select the first thing that comes back. 909 00:42:41,030 --> 00:42:44,510 For instance, if we wanted to select from our table of users 910 00:42:44,510 --> 00:42:47,090 and we only wanted to get back the one user that 911 00:42:47,090 --> 00:42:51,290 matches a particular username, well, the syntax for that might look something 912 00:42:51,290 --> 00:42:54,860 like Limit 1, to say, only return back one thing. 913 00:42:54,860 --> 00:42:58,820 And the way we would do that in SQLAlchemy is just to say, 914 00:42:58,820 --> 00:43:02,030 after we have Flight.query.filtery_byorigin=Pairs, 915 00:43:02,030 --> 00:43:05,120 to mean, select from flights where the origin is Paris-- 916 00:43:05,120 --> 00:43:09,170 .first is a special method that's built in to SQLAlchemy to say, 917 00:43:09,170 --> 00:43:11,390 just extract that first result. And so then, 918 00:43:11,390 --> 00:43:14,180 what you'll get back is not a list, like we just saw a moment ago, 919 00:43:14,180 --> 00:43:16,670 but actually just that first thing that returned back. 920 00:43:16,670 --> 00:43:19,640 And if there was nothing that met that particular filter-by-query, 921 00:43:19,640 --> 00:43:22,460 if there was no flight whose origin was Paris, 922 00:43:22,460 --> 00:43:27,050 then .first is going to give back None, as in nothing got returned. 923 00:43:27,050 --> 00:43:30,524 Other things that we can do-- 924 00:43:30,524 --> 00:43:33,440 if we want to do Select count star-- this is something we saw before-- 925 00:43:33,440 --> 00:43:36,890 if we wanted to look at how many rows actually match this particular 926 00:43:36,890 --> 00:43:40,880 property, we can do that via .count after the filter by. 927 00:43:40,880 --> 00:43:44,160 So Flight.query.filter_byorigin=Paris stays the same. 928 00:43:44,160 --> 00:43:46,700 And then the added line, .count, is going to say, 929 00:43:46,700 --> 00:43:53,640 just return to me the number of rows that matched that filter by constraint. 930 00:43:53,640 --> 00:43:54,880 Other things we can do. 931 00:43:54,880 --> 00:43:57,450 Select star from flights where ID equals 28-- 932 00:43:57,450 --> 00:44:00,270 this is a common paradigm where we want to select something 933 00:44:00,270 --> 00:44:01,436 by its individual ID. 934 00:44:01,436 --> 00:44:03,310 We've already seen a way that we can do this. 935 00:44:03,310 --> 00:44:07,950 We can use Flight.query.filter_by(ID=28).first 936 00:44:07,950 --> 00:44:10,230 to mean, query my flights table. 937 00:44:10,230 --> 00:44:13,440 Filter it out, so that I'm only getting the things whose ID is 28. 938 00:44:13,440 --> 00:44:14,830 And get me the first thing. 939 00:44:14,830 --> 00:44:16,840 But this paradigm is so common in SQLAlchemy-- 940 00:44:16,840 --> 00:44:21,270 so often it is that you want to take and extract from a table just one 941 00:44:21,270 --> 00:44:24,630 particular row by its primary key, by its ID column, 942 00:44:24,630 --> 00:44:27,760 that SQLAlchemy has a built-in way to do this even more efficiently, 943 00:44:27,760 --> 00:44:30,300 which is just Flight.query.get(28). 944 00:44:30,300 --> 00:44:33,510 And so this line, Flight.query.get(28), is going to say, 945 00:44:33,510 --> 00:44:37,620 get me the flight whose ID is 28, and just return that object or none, 946 00:44:37,620 --> 00:44:39,790 if there is nothing with ID 28. 947 00:44:39,790 --> 00:44:42,900 And so this can often be a much conciser way 948 00:44:42,900 --> 00:44:47,367 to extract information out of a table if you just want to get it by its ID. 949 00:44:47,367 --> 00:44:49,200 Questions about these Select queries and how 950 00:44:49,200 --> 00:44:52,255 we able to translate them into SQLAlchemy syntax? 951 00:44:52,255 --> 00:44:54,630 And again, no need to worry about memorizing all of this. 952 00:44:54,630 --> 00:44:56,920 The slides will be posted-- the source code as well. 953 00:44:56,920 --> 00:45:00,330 So you can reference them as you think about how to perform your own queries. 954 00:45:00,330 --> 00:45:04,835 But questions about the ideas so far in these Select queries? 955 00:45:04,835 --> 00:45:06,960 OK, so we've looked at selecting data from a table. 956 00:45:06,960 --> 00:45:09,090 We've looked at inserting data into a table. 957 00:45:09,090 --> 00:45:10,560 We've looked at creating tables. 958 00:45:10,560 --> 00:45:14,610 What about updating a table in order to change 959 00:45:14,610 --> 00:45:18,085 the values inside of the columns of a particular row inside our database? 960 00:45:18,085 --> 00:45:20,460 Well before, that would have looked something like this-- 961 00:45:20,460 --> 00:45:24,440 update flights set duration equals 280 where ID equals 6. 962 00:45:24,440 --> 00:45:27,240 We would have gotten flight with ID 6 and changed its duration 963 00:45:27,240 --> 00:45:29,040 to be some other duration. 964 00:45:29,040 --> 00:45:31,860 How might we do that using our classes and objects 965 00:45:31,860 --> 00:45:35,460 in this object-relational mapping that we're looking at in Python? 966 00:45:35,460 --> 00:45:39,600 Well, we might do something like this. flight=Flight.query.get(6). 967 00:45:39,600 --> 00:45:42,090 We saw before, that is just going to extract 968 00:45:42,090 --> 00:45:44,730 for us the flight whose ID is 6. 969 00:45:44,730 --> 00:45:48,160 And now that we have this flight object, we can manipulate its properties. 970 00:45:48,160 --> 00:45:52,990 When we say Flight.duration=280, that is telling my flight object, 971 00:45:52,990 --> 00:45:54,782 update your duration to be 280. 972 00:45:54,782 --> 00:45:57,240 And that will have the effect of running this Update query. 973 00:45:57,240 --> 00:46:00,510 We'll need to commit our changes at the end, like we did in the examples 974 00:46:00,510 --> 00:46:01,350 before. 975 00:46:01,350 --> 00:46:04,920 But this will have the effect of updating individual columns inside 976 00:46:04,920 --> 00:46:06,639 of our table. 977 00:46:06,639 --> 00:46:08,430 Likewise, if we wanted to delete something, 978 00:46:08,430 --> 00:46:13,140 like delete from flights where ID equals 28, we could query for the 20th flight. 979 00:46:13,140 --> 00:46:17,245 And then db.session.delete is sort of the opposite of db.session.add. 980 00:46:17,245 --> 00:46:20,310 It will take an item, and it will delete it from our table. 981 00:46:20,310 --> 00:46:23,520 And so now we've been able to recreate all of the same things 982 00:46:23,520 --> 00:46:26,640 that we were able to do, using just raw SQL, 983 00:46:26,640 --> 00:46:30,720 by using this Python syntax and SQLAlchemy that 984 00:46:30,720 --> 00:46:32,295 helps to make things a little easier. 985 00:46:32,295 --> 00:46:34,350 I'll go through a couple other quick pieces 986 00:46:34,350 --> 00:46:35,809 of the syntax that might be useful. 987 00:46:35,809 --> 00:46:37,933 But then I want to dive into a couple more examples 988 00:46:37,933 --> 00:46:40,660 to give you a better sense for how this would actually work. 989 00:46:40,660 --> 00:46:42,960 So at the end, when you're done making your changes 990 00:46:42,960 --> 00:46:45,209 and you want to commit your changes and you ordinarily 991 00:46:45,209 --> 00:46:47,730 would have written Commit inside of your SQL syntax, 992 00:46:47,730 --> 00:46:50,340 db.session.commit is the syntax for doing that. 993 00:46:50,340 --> 00:46:53,280 And we saw an example of that in the example 994 00:46:53,280 --> 00:46:56,730 before, when we were inserting rows into our database. 995 00:46:56,730 --> 00:47:00,780 What if we wanted to have slightly more advanced queries when we're 996 00:47:00,780 --> 00:47:02,730 selecting information from our table? 997 00:47:02,730 --> 00:47:05,670 So we saw before, maybe we want to select 998 00:47:05,670 --> 00:47:09,600 all of our flights in a particular order-- order them by their origin 999 00:47:09,600 --> 00:47:11,570 in a particular order. 1000 00:47:11,570 --> 00:47:13,080 That might look something like this. 1001 00:47:13,080 --> 00:47:15,960 Instead of filter by, our SQLAlchemy syntax 1002 00:47:15,960 --> 00:47:19,530 also has an Order By method that allows us to order 1003 00:47:19,530 --> 00:47:20,890 our flights in a particular way. 1004 00:47:20,890 --> 00:47:24,870 So in this case Flight.query.order_by(Flight.origin) 1005 00:47:24,870 --> 00:47:27,840 says query from the Flights table, put them in a particular order, 1006 00:47:27,840 --> 00:47:30,960 sort them by the origin column of the Flights table, 1007 00:47:30,960 --> 00:47:33,010 and get me back all of the results. 1008 00:47:33,010 --> 00:47:36,090 If we wanted it in reverse order, origin descending, 1009 00:47:36,090 --> 00:47:40,870 we would just add the .desc for Descending syntax into there as well. 1010 00:47:40,870 --> 00:47:46,200 And so order_by(Flight.origin.desc) is going to query for all the flights. 1011 00:47:46,200 --> 00:47:51,780 And we'll get back a list in reverse alphabetical order by their origin. 1012 00:47:51,780 --> 00:47:54,660 What about something like this, Select star from flights 1013 00:47:54,660 --> 00:47:56,940 where origin is not equal to Paris? 1014 00:47:56,940 --> 00:47:59,640 Well, inside of our filter by constraints 1015 00:47:59,640 --> 00:48:02,356 that we saw before, we were only ever able to say that something 1016 00:48:02,356 --> 00:48:03,480 is equal to something else. 1017 00:48:03,480 --> 00:48:06,180 When we're running a Python method, we can 1018 00:48:06,180 --> 00:48:09,480 pass in our parameters of what we want different parameter 1019 00:48:09,480 --> 00:48:10,450 values to be equal to. 1020 00:48:10,450 --> 00:48:13,200 But we don't really have a way of specifying that something is not 1021 00:48:13,200 --> 00:48:14,970 equal to something, for instance. 1022 00:48:14,970 --> 00:48:18,210 And so SQLAlchemy offers more advanced ways to perform queries. 1023 00:48:18,210 --> 00:48:19,890 In particular-- confusingly enough-- 1024 00:48:19,890 --> 00:48:22,650 they call this filter, instead of filter by. 1025 00:48:22,650 --> 00:48:24,660 You'll see the slight nuance here. 1026 00:48:24,660 --> 00:48:28,440 So what the syntax looks like here is Flight.query.filter. 1027 00:48:28,440 --> 00:48:33,240 And then, inside a filter, I can put in arbitrary Boolean expressions 1028 00:48:33,240 --> 00:48:35,310 that are going to evaluate to True or False 1029 00:48:35,310 --> 00:48:38,160 on a particular flight and query that way. 1030 00:48:38,160 --> 00:48:42,720 So I can say Flight.query.filter flight.origin not equal to Paris 1031 00:48:42,720 --> 00:48:45,270 and then extract all from there to say, query 1032 00:48:45,270 --> 00:48:49,380 from the flights table for anything whose origin is not Paris. 1033 00:48:49,380 --> 00:48:52,750 And so this is allowable syntax in SQLAlchemy as well. 1034 00:48:52,750 --> 00:48:56,130 And as a result of that, you can begin to have 1035 00:48:56,130 --> 00:48:58,664 analogs for some of the more complicated Select expressions 1036 00:48:58,664 --> 00:48:59,830 that we looked at last week. 1037 00:48:59,830 --> 00:49:02,640 So we looked at, how do you select all flights whose origin 1038 00:49:02,640 --> 00:49:04,680 contain the letter A within them? 1039 00:49:04,680 --> 00:49:08,550 There is likewise a way to do Flight.origin.like, 1040 00:49:08,550 --> 00:49:11,820 which simulates that same effect and has the effect of performing 1041 00:49:11,820 --> 00:49:16,050 that Like query that we saw in SQL just last time. 1042 00:49:16,050 --> 00:49:19,240 And I'll go through a couple others very quickly. 1043 00:49:19,240 --> 00:49:23,160 Select star from flights where origin is in Tokyo and Paris. 1044 00:49:23,160 --> 00:49:24,660 That looks something like this. 1045 00:49:24,660 --> 00:49:26,940 Again, we're going to do Flight.query.filter. 1046 00:49:26,940 --> 00:49:30,800 And then inside of the filter, we have Flight.origin.in_-- 1047 00:49:30,800 --> 00:49:33,720 in with an underscore, because in happens to be a Python keywords, 1048 00:49:33,720 --> 00:49:35,730 so the underscore helps to differentiate it-- 1049 00:49:35,730 --> 00:49:37,560 and then just this list, Tokyo and Paris. 1050 00:49:37,560 --> 00:49:39,120 This is just a Python list. 1051 00:49:39,120 --> 00:49:43,260 And we're saying, query for where the flight's origin is 1052 00:49:43,260 --> 00:49:46,440 in this list of possible origins. 1053 00:49:46,440 --> 00:49:50,190 We can also do Boolean expressions that are a compound, that have ands 1054 00:49:50,190 --> 00:49:52,590 and ors in them in much the same way. 1055 00:49:52,590 --> 00:49:56,520 We can specify "and" to mean, make sure that both of these constraints 1056 00:49:56,520 --> 00:49:58,950 are true when we're trying to query for something. 1057 00:49:58,950 --> 00:50:02,940 And likewise, we can say "or", to specify that one or the other 1058 00:50:02,940 --> 00:50:04,030 needs to be true. 1059 00:50:04,030 --> 00:50:07,110 These ands and ors are special SQLAlchemy syntax 1060 00:50:07,110 --> 00:50:09,250 that you'll need to import at the top of your file. 1061 00:50:09,250 --> 00:50:10,540 But no need to worry about them too much. 1062 00:50:10,540 --> 00:50:12,873 They will come up in some of your more advanced queries. 1063 00:50:12,873 --> 00:50:16,350 But in large part, you can likely get away 1064 00:50:16,350 --> 00:50:21,730 with just using the filter by syntax that we've been looking at earlier. 1065 00:50:21,730 --> 00:50:25,200 And finally, we'll look at one more example, an example 1066 00:50:25,200 --> 00:50:27,220 of joining multiple tables together. 1067 00:50:27,220 --> 00:50:29,280 So this is an example we saw from last time, 1068 00:50:29,280 --> 00:50:32,520 where we wanted to combine data from our Flights and Passengers table. 1069 00:50:32,520 --> 00:50:35,454 And we want to combine them on a particular constraint. 1070 00:50:35,454 --> 00:50:38,370 How does our query know how the Flights table and the Passengers table 1071 00:50:38,370 --> 00:50:39,240 are related? 1072 00:50:39,240 --> 00:50:43,350 Well, in particular, we want to make sure that the ID of our Flights table 1073 00:50:43,350 --> 00:50:51,601 corresponds with the Flight ID of our Passengers table. 1074 00:50:51,601 --> 00:50:53,350 And so the way that we would ultimately do 1075 00:50:53,350 --> 00:50:56,972 that is via syntax like this-- db.session.query. 1076 00:50:56,972 --> 00:50:58,930 We're going to query for multiple tables, query 1077 00:50:58,930 --> 00:51:01,780 for the Flight table and the Passengers table. 1078 00:51:01,780 --> 00:51:04,570 And we're going to filter it such that the flight ID needs to be 1079 00:51:04,570 --> 00:51:06,550 equal to the passengers' flight ID. 1080 00:51:06,550 --> 00:51:09,130 And we're going to select everything from there. 1081 00:51:09,130 --> 00:51:12,340 So-- so far, that's just been a lot more syntax. 1082 00:51:12,340 --> 00:51:14,392 It's not altogether clear, just yet, why this 1083 00:51:14,392 --> 00:51:16,600 is any better than what we've seen before, because it 1084 00:51:16,600 --> 00:51:18,670 seems like it's just different syntax. 1085 00:51:18,670 --> 00:51:22,360 It seems, maybe, a little bit simpler, but still verbose. 1086 00:51:22,360 --> 00:51:24,164 So why is this actually more powerful? 1087 00:51:24,164 --> 00:51:26,080 Well, let's take a look at how we can actually 1088 00:51:26,080 --> 00:51:29,170 begin to use some of this syntax in order 1089 00:51:29,170 --> 00:51:32,060 to do more interesting and more powerful things. 1090 00:51:32,060 --> 00:51:37,780 So let's take a look at the airline website example that we used last time, 1091 00:51:37,780 --> 00:51:43,030 where we wanted to create a website that lets people register for flights 1092 00:51:43,030 --> 00:51:46,240 and then view who is registered for a given flight. 1093 00:51:46,240 --> 00:51:49,030 So we'll go into Airline1, which is the same as an example 1094 00:51:49,030 --> 00:51:52,870 that we saw last time, just so we can recall what happens in Airline1. 1095 00:51:52,870 --> 00:51:55,300 When we run this program, we get this Book 1096 00:51:55,300 --> 00:51:58,090 a Flight page that shows me a list of all of the flights 1097 00:51:58,090 --> 00:52:00,380 that I currently have inside of my table. 1098 00:52:00,380 --> 00:52:04,455 And if I type in a passenger name, like Alice, and book the flight, 1099 00:52:04,455 --> 00:52:05,080 it's a success. 1100 00:52:05,080 --> 00:52:06,400 You've now booked your flight. 1101 00:52:06,400 --> 00:52:09,990 And that was all that Airline1 did for us. 1102 00:52:09,990 --> 00:52:14,350 It also had /flights, which was a route we could go to that would list out all 1103 00:52:14,350 --> 00:52:15,500 of our different flights. 1104 00:52:15,500 --> 00:52:17,626 And if I clicked on Paris to New York, for example, 1105 00:52:17,626 --> 00:52:20,500 it would give me details about that flight-- the origin, destination, 1106 00:52:20,500 --> 00:52:21,880 and duration, and the passenger. 1107 00:52:21,880 --> 00:52:24,370 And this was all code that we wrote last time. 1108 00:52:24,370 --> 00:52:28,060 But we're going to look at ways we can now improve upon that code this time. 1109 00:52:28,060 --> 00:52:31,180 Inside of Airline2, we're going to look at application.py 1110 00:52:31,180 --> 00:52:33,260 and see what's going on inside of application.py. 1111 00:52:33,260 --> 00:52:36,190 I'm just using a text editor inside of my terminal window for now. 1112 00:52:36,190 --> 00:52:38,710 And so what we're doing up here in the first couple lines 1113 00:52:38,710 --> 00:52:43,510 is just configuring the database to interact with our Flask application, 1114 00:52:43,510 --> 00:52:46,930 in much the same way as you saw in some of the command line programs. 1115 00:52:46,930 --> 00:52:52,040 But now, what's going on inside of some of these individual functions? 1116 00:52:52,040 --> 00:52:53,510 Let's take a look. 1117 00:52:53,510 --> 00:52:56,792 So in particular, our Index page, this original route 1118 00:52:56,792 --> 00:52:58,750 where we just went to our website and we wanted 1119 00:52:58,750 --> 00:53:00,375 to list out all of the flights-- right? 1120 00:53:00,375 --> 00:53:03,340 We wanted that dropdown box that let us select an individual flight we 1121 00:53:03,340 --> 00:53:07,030 wanted to register for and type in a passenger name and booked that flight. 1122 00:53:07,030 --> 00:53:10,820 We needed to first query for all of the flights that we wanted. 1123 00:53:10,820 --> 00:53:14,800 And so now, using SQLAlchemy the syntax for doing that is just to say, 1124 00:53:14,800 --> 00:53:20,629 flights=Flight.query.all, to mean, select all of that flight information. 1125 00:53:20,629 --> 00:53:22,420 And now that we have this variable flights, 1126 00:53:22,420 --> 00:53:25,451 we can pass it into our index.html template. 1127 00:53:25,451 --> 00:53:28,450 So that that template that displays the dropdown list of all the flights 1128 00:53:28,450 --> 00:53:31,090 that let us book a particular flight for a passenger 1129 00:53:31,090 --> 00:53:33,570 has access to the result of that query. 1130 00:53:33,570 --> 00:53:35,500 And so that was querying for everything. 1131 00:53:35,500 --> 00:53:39,550 And then, recall that, when a user selected a flight from the dropdown 1132 00:53:39,550 --> 00:53:42,940 list, typed in their name, and clicked Book Flight, what happened? 1133 00:53:42,940 --> 00:53:48,220 Well, it sent a request to this Book route via the Post HTTP Request method. 1134 00:53:48,220 --> 00:53:50,230 And what's happening inside the Book route? 1135 00:53:50,230 --> 00:53:53,740 Well, just like before-- and you can look to last time for more explanation 1136 00:53:53,740 --> 00:53:54,370 on that-- 1137 00:53:54,370 --> 00:53:57,447 we're going to extract from the form the person's name-- 1138 00:53:57,447 --> 00:53:59,530 because I typed in their name into that HTML form. 1139 00:53:59,530 --> 00:54:03,790 And I want to get that name, so that I can insert it into the database. 1140 00:54:03,790 --> 00:54:07,540 And we're going to try to get the flight ID by making sure 1141 00:54:07,540 --> 00:54:10,540 that whatever they passed in, whatever flight they picked, 1142 00:54:10,540 --> 00:54:12,700 is actually an integer. 1143 00:54:12,700 --> 00:54:16,720 And then, down here, we're going to make sure that the flight actually exists. 1144 00:54:16,720 --> 00:54:18,730 So what we're going to do is, if they say, 1145 00:54:18,730 --> 00:54:22,120 I want to register Alice for flight number 1, the first thing I should do 1146 00:54:22,120 --> 00:54:24,740 is make sure that flight number 1 actually exists. 1147 00:54:24,740 --> 00:54:26,920 So on line 28 here at the bottom, I've said, 1148 00:54:26,920 --> 00:54:30,520 Flight=Flight.query.get(Flight_id). 1149 00:54:30,520 --> 00:54:33,550 Recall that Flight.query.get was our method of saying, 1150 00:54:33,550 --> 00:54:37,040 extract from the Flights table the thing that has a particular ID. 1151 00:54:37,040 --> 00:54:40,180 And here, we're just extracting whatever has ID Flight ID. 1152 00:54:40,180 --> 00:54:43,690 And so this is more concise than our previous Select star from flights 1153 00:54:43,690 --> 00:54:48,650 where ID equals whatever Flight ID was and needing to pass that in separately. 1154 00:54:48,650 --> 00:54:51,430 So this allows us to extract that flight. 1155 00:54:51,430 --> 00:54:58,810 And now, if that flight is None-- 1156 00:54:58,810 --> 00:55:01,060 in other words, if we didn't get anything back-- 1157 00:55:01,060 --> 00:55:02,650 we're going to return an Error page. 1158 00:55:02,650 --> 00:55:06,110 But otherwise, we're going to add a passenger to our flight. 1159 00:55:06,110 --> 00:55:09,160 So we're saying, passenger equals new passenger, 1160 00:55:09,160 --> 00:55:12,520 whose name is Name and whose flight ID is .flight_id. 1161 00:55:12,520 --> 00:55:15,370 We're creating a new passenger, just like we have previously. 1162 00:55:15,370 --> 00:55:19,120 Then db.session.add(passenger) says, insert this passenger 1163 00:55:19,120 --> 00:55:21,130 into my Passengers table. 1164 00:55:21,130 --> 00:55:22,780 And then commit those changes. 1165 00:55:22,780 --> 00:55:24,340 And then we return. 1166 00:55:24,340 --> 00:55:26,530 It's been successful. 1167 00:55:26,530 --> 00:55:29,800 Likewise, inside of our Flights route, in order to list all the flights, 1168 00:55:29,800 --> 00:55:32,369 we're going to again use Flight.query.all to list out 1169 00:55:32,369 --> 00:55:35,410 all those flights, so that we can display a listing of all those flights. 1170 00:55:35,410 --> 00:55:38,810 And when someone clicks on an individual flight, what needs to happen? 1171 00:55:38,810 --> 00:55:41,500 Well, once again, we need to make sure the flight exists, 1172 00:55:41,500 --> 00:55:44,050 during Flight.query.get(flight_id). 1173 00:55:44,050 --> 00:55:47,020 And then we need to get all of the passengers on that flight. 1174 00:55:47,020 --> 00:55:51,460 Recall that on our individual page here, in addition 1175 00:55:51,460 --> 00:55:53,570 to information about the flight, we also listed 1176 00:55:53,570 --> 00:55:56,730 who is on that flight, who are the passengers that are on this flight. 1177 00:55:56,730 --> 00:56:00,520 And so, to do that, we can use a line like line 56 here. 1178 00:56:00,520 --> 00:56:04,690 Passengers=Passenger.query.filter_by. 1179 00:56:04,690 --> 00:56:07,900 So I'm querying the Passenger table under certain constraints. 1180 00:56:07,900 --> 00:56:13,240 And in particular, I'm querying it where flight ID is equal to this flight ID 1181 00:56:13,240 --> 00:56:14,890 and then getting back all the results. 1182 00:56:14,890 --> 00:56:19,090 So I'm querying for all of the passengers whose flight ID matches 1183 00:56:19,090 --> 00:56:21,340 whatever flight I'm trying to view. 1184 00:56:21,340 --> 00:56:25,420 And then after that, I'm going to return the flight.html template, 1185 00:56:25,420 --> 00:56:30,251 passing in all of that information about those individual passengers. 1186 00:56:30,251 --> 00:56:32,000 So a lot of this is the same as last time. 1187 00:56:32,000 --> 00:56:34,000 But we've made a couple of slight modifications. 1188 00:56:34,000 --> 00:56:36,430 In particular, notice that there is no raw SQL 1189 00:56:36,430 --> 00:56:38,800 queries actually inside of this code. 1190 00:56:38,800 --> 00:56:42,220 I'm just using SQLAlchemy and using the power of this ORM 1191 00:56:42,220 --> 00:56:48,160 to use classes and objects to be able to insert and select from my database. 1192 00:56:48,160 --> 00:56:50,440 But questions about how any of that is working so far? 1193 00:56:50,440 --> 00:56:53,620 1194 00:56:53,620 --> 00:56:57,410 OK, so one of the powerful features of the ORM, 1195 00:56:57,410 --> 00:56:59,810 in addition to just letting us avoid SQL syntax, 1196 00:56:59,810 --> 00:57:02,240 is that, because we now have classes, we can 1197 00:57:02,240 --> 00:57:07,477 begin to define specific behavior that we can add to individual classes. 1198 00:57:07,477 --> 00:57:09,560 Recall that, way back in the beginning of lecture, 1199 00:57:09,560 --> 00:57:11,676 we started with a very generic Flight class. 1200 00:57:11,676 --> 00:57:13,550 And then we gave the Flight class the ability 1201 00:57:13,550 --> 00:57:15,920 to add a passenger, for instance. 1202 00:57:15,920 --> 00:57:21,520 Let's try not to do the same thing with our web application here. 1203 00:57:21,520 --> 00:57:25,010 So we'll take a look at Airline3. 1204 00:57:25,010 --> 00:57:28,220 And in particular, let's take a look at models.py. 1205 00:57:28,220 --> 00:57:33,500 So what we have here is our Flight class, same as before. 1206 00:57:33,500 --> 00:57:36,740 Our flight class is going to have an ID, origin, destination, and duration. 1207 00:57:36,740 --> 00:57:40,340 But we can now add functionality, add features to our models. 1208 00:57:40,340 --> 00:57:44,580 In particular, lets add an Add Passenger method to our Flight class. 1209 00:57:44,580 --> 00:57:47,480 This Add Passenger method is going to take self as a parameter, 1210 00:57:47,480 --> 00:57:50,750 as well as the name of the passenger that we want to add. 1211 00:57:50,750 --> 00:57:53,980 And so what's going to happen now inside of Add Passenger-- 1212 00:57:53,980 --> 00:57:56,370 well, to add a passenger, how do we do it? 1213 00:57:56,370 --> 00:57:58,370 We start with creating a new passenger. 1214 00:57:58,370 --> 00:57:59,870 It's a Passenger class. 1215 00:57:59,870 --> 00:58:02,270 The name is whatever the name that was passed in. 1216 00:58:02,270 --> 00:58:06,320 What is the flight ID that we should give to this passenger? 1217 00:58:06,320 --> 00:58:10,280 Well, because we have access to self, where self is the individual flight, 1218 00:58:10,280 --> 00:58:13,880 we can get at the relevant flight ID by doing self.id, 1219 00:58:13,880 --> 00:58:19,280 because self is the flight and self.id is whatever ID that current flight has. 1220 00:58:19,280 --> 00:58:21,980 And so, P equals Passenger, whose name is Name 1221 00:58:21,980 --> 00:58:27,440 and whose flight ID is whatever the ID of the current flight is. 1222 00:58:27,440 --> 00:58:31,610 After that, we db.session.add(P) to say, insert this new passenger 1223 00:58:31,610 --> 00:58:32,840 into the database. 1224 00:58:32,840 --> 00:58:35,670 And now, commit those changes. 1225 00:58:35,670 --> 00:58:39,140 So now, by adding this method to the Flight class that wasn't here before, 1226 00:58:39,140 --> 00:58:42,150 I have given the flight the ability to add a new passenger. 1227 00:58:42,150 --> 00:58:44,840 I've given it the instructions for how to take a name 1228 00:58:44,840 --> 00:58:47,450 and actually add a passenger to the database. 1229 00:58:47,450 --> 00:58:50,480 And so before, while in my application.py code, 1230 00:58:50,480 --> 00:58:54,230 I needed to explicitly create a new passenger, add it to the database, 1231 00:58:54,230 --> 00:58:58,940 commit those changes, now inside of application.py-- 1232 00:58:58,940 --> 00:59:02,422 if I go down to this Book function, which 1233 00:59:02,422 --> 00:59:04,880 is what happens when the user types in their name and says, 1234 00:59:04,880 --> 00:59:06,620 I want to book a flight now. 1235 00:59:06,620 --> 00:59:10,430 After we verify that the flight exists, all we need to do, 1236 00:59:10,430 --> 00:59:13,520 after we verify the flight exists, to actually add the passenger, 1237 00:59:13,520 --> 00:59:15,730 is this line here on line 33-- 1238 00:59:15,730 --> 00:59:18,890 Flight.add_passenger(name). 1239 00:59:18,890 --> 00:59:21,200 Name is that name of the passenger we wanted to add. 1240 00:59:21,200 --> 00:59:24,760 And flight.add_passenger(name) take care of everything we need to do to add 1241 00:59:24,760 --> 00:59:26,630 a new passenger to this flight. 1242 00:59:26,630 --> 00:59:28,790 Because the Add Passenger method that we wrote 1243 00:59:28,790 --> 00:59:32,210 knows how to take the ID of the flight and associate it 1244 00:59:32,210 --> 00:59:34,719 as the flight ID of the passenger. 1245 00:59:34,719 --> 00:59:37,010 And it knows how to add that passenger to the database, 1246 00:59:37,010 --> 00:59:38,600 if I had db.session.add. 1247 00:59:38,600 --> 00:59:40,370 And it commits those changes for us. 1248 00:59:40,370 --> 00:59:42,770 So this line alone is all we need to actually do 1249 00:59:42,770 --> 00:59:46,040 in order to add that new passenger to the flight. 1250 00:59:46,040 --> 00:59:51,210 So if we try it out, go to Flask run, go back to this page. 1251 00:59:51,210 --> 01:00:00,500 Let's make sure-- oh, go into Airline3 first, Flask run. 1252 01:00:00,500 --> 01:00:04,590 And I try and register Bob for the flight from Paris to New York. 1253 01:00:04,590 --> 01:00:06,080 I've now booked that flight. 1254 01:00:06,080 --> 01:00:09,210 If I now go into flights and click on Paris to New York, 1255 01:00:09,210 --> 01:00:12,200 Bob now appears, because I called that Add Passenger 1256 01:00:12,200 --> 01:00:15,976 method from application.py. 1257 01:00:15,976 --> 01:00:17,600 Questions about how or why that worked? 1258 01:00:17,600 --> 01:00:20,240 1259 01:00:20,240 --> 01:00:24,050 OK, let's look at one more particularly powerful and compelling feature 1260 01:00:24,050 --> 01:00:24,590 of ORMs. 1261 01:00:24,590 --> 01:00:26,006 And then we'll take a short break. 1262 01:00:26,006 --> 01:00:28,670 And this is going to be the concept of relationships. 1263 01:00:28,670 --> 01:00:31,490 And so, relationships in SQLAlchemy are going 1264 01:00:31,490 --> 01:00:36,050 to be an easy way of taking one table and relating it 1265 01:00:36,050 --> 01:00:39,900 to another table to give them some way of referring to each other. 1266 01:00:39,900 --> 01:00:42,240 So what is that going to look like? 1267 01:00:42,240 --> 01:00:47,980 Let's go into the Airline4 and take a look at models 1268 01:00:47,980 --> 01:00:50,162 and take a look at this Flight class. 1269 01:00:50,162 --> 01:00:53,120 Everything about this is the same as the flight class that we just saw, 1270 01:00:53,120 --> 01:00:54,710 with one key exception. 1271 01:00:54,710 --> 01:00:57,530 In addition to an ID, origin, destination, and duration, 1272 01:00:57,530 --> 01:01:01,430 I've added a property to my flight class called Passengers. 1273 01:01:01,430 --> 01:01:04,070 Now, Passengers is not a column on my Flights table. 1274 01:01:04,070 --> 01:01:07,100 Recall, my Flights table has an Origin column, a Destination column, 1275 01:01:07,100 --> 01:01:10,320 a Duration column, and an ID column that keeps track of what number flight 1276 01:01:10,320 --> 01:01:11,840 it is, but nothing else. 1277 01:01:11,840 --> 01:01:14,840 This Passenger, as a property of my flight, 1278 01:01:14,840 --> 01:01:18,500 is just something that exists inside of my Python code. 1279 01:01:18,500 --> 01:01:21,980 And in particular, I'm defining it to be a relationship, a relationship that 1280 01:01:21,980 --> 01:01:24,660 is going to connect multiple tables together. 1281 01:01:24,660 --> 01:01:26,570 And in this case, that relationship is going 1282 01:01:26,570 --> 01:01:31,230 to be a relationship between the Flight table and the Passenger table. 1283 01:01:31,230 --> 01:01:34,610 And what this is going to do is give me a way such that, 1284 01:01:34,610 --> 01:01:39,950 if I have a flight object, I can use this passenger's property 1285 01:01:39,950 --> 01:01:45,530 to extract all of the passengers that are on that particular flight. 1286 01:01:45,530 --> 01:01:48,239 Backref=Flight is going to do something else. 1287 01:01:48,239 --> 01:01:51,030 And it's going to give me a relationship in the opposite direction. 1288 01:01:51,030 --> 01:01:54,680 In particular, if I have a passenger-- and let's call that passenger P, 1289 01:01:54,680 --> 01:01:55,700 for example-- 1290 01:01:55,700 --> 01:01:59,270 and I want to access the flight that that passenger is associated with, 1291 01:01:59,270 --> 01:02:02,660 rather than say, as we would have needed to before, 1292 01:02:02,660 --> 01:02:07,460 p.flight_id is the ID of the flight the passenger is associated with-- 1293 01:02:07,460 --> 01:02:11,240 so if I wanted to extract that flight, I would need to do syntax like 1294 01:02:11,240 --> 01:02:17,150 Flight.query.get(P.FlightID), which is the ID of the flight. 1295 01:02:17,150 --> 01:02:18,920 Instead, I'm just going to be able to use 1296 01:02:18,920 --> 01:02:24,050 the keyword Flight to access the flight information for that passenger. 1297 01:02:24,050 --> 01:02:28,790 And then finally, this lazy=true says that I want this to lazy evaluate. 1298 01:02:28,790 --> 01:02:33,630 In other words, if I don't ever try to access the passengers of a flight, 1299 01:02:33,630 --> 01:02:36,830 there is no reason to waste time and operation on the database 1300 01:02:36,830 --> 01:02:40,270 by trying to actually extract all those passengers from the database. 1301 01:02:40,270 --> 01:02:42,440 Lazy=true says, be lazy about it. 1302 01:02:42,440 --> 01:02:44,085 This passenger's property exists. 1303 01:02:44,085 --> 01:02:47,210 But don't worry about fetching that information, unless I actually need it. 1304 01:02:47,210 --> 01:02:51,031 When I try to use the passenger as property of a flight, then-- yeah-- now 1305 01:02:51,031 --> 01:02:51,530 I need it. 1306 01:02:51,530 --> 01:02:53,488 Now, go ahead and extract it from the database. 1307 01:02:53,488 --> 01:02:56,900 But until I do, don't worry about trying to get access to that information. 1308 01:02:56,900 --> 01:02:58,910 So that's just a little efficiency bonus, 1309 01:02:58,910 --> 01:03:01,820 in case we don't need to use that property. 1310 01:03:01,820 --> 01:03:02,780 So how is this useful? 1311 01:03:02,780 --> 01:03:04,310 What does this allow us to do? 1312 01:03:04,310 --> 01:03:05,870 Well, let's take a look. 1313 01:03:05,870 --> 01:03:13,190 Recall that before, inside of Airline3 inside of application.py, 1314 01:03:13,190 --> 01:03:17,090 when we were trying to extract all of the passenger information 1315 01:03:17,090 --> 01:03:20,630 for an individual flight, to list out all the passengers on that flight, 1316 01:03:20,630 --> 01:03:22,480 the line looked something like this-- 1317 01:03:22,480 --> 01:03:28,430 passengers=Passenger.query.filter by(flight id=flight id).all. 1318 01:03:28,430 --> 01:03:33,080 I was extracting all of the passengers that had this particular flight ID. 1319 01:03:33,080 --> 01:03:36,290 And I was getting all of those passengers. 1320 01:03:36,290 --> 01:03:40,070 So how might I do this now that I have relationships? 1321 01:03:40,070 --> 01:03:43,070 Well, inside of Airline4's application.py, 1322 01:03:43,070 --> 01:03:44,500 the line looks like this. 1323 01:03:44,500 --> 01:03:48,590 On line 54, when I want to get all the passengers, all I need to say 1324 01:03:48,590 --> 01:03:51,770 is, I have this flight already, this flight object, 1325 01:03:51,770 --> 01:03:53,870 which I extracted from the database. 1326 01:03:53,870 --> 01:03:58,520 And now, Passengers is just going to be equal to flight.passengers. 1327 01:03:58,520 --> 01:04:02,420 I added that passenger as property to my Flights table. 1328 01:04:02,420 --> 01:04:04,880 And so now, just by using that dot notation, 1329 01:04:04,880 --> 01:04:08,180 I can extract out all of the passengers that are on that flight 1330 01:04:08,180 --> 01:04:10,730 and then pass it into the template. 1331 01:04:10,730 --> 01:04:15,352 So that helps to allow me to be much more concise with my queries. 1332 01:04:15,352 --> 01:04:17,060 Rather than that long thing I had before, 1333 01:04:17,060 --> 01:04:20,300 I can just say flight.passengers to get me all of the passengers that 1334 01:04:20,300 --> 01:04:22,040 were on that flight. 1335 01:04:22,040 --> 01:04:26,570 So let's see an example of that in action. 1336 01:04:26,570 --> 01:04:31,640 If I go back to this main URL and I want to register someone on the flight from 1337 01:04:31,640 --> 01:04:33,530 Paris to New York-- we'll say, Chad-- 1338 01:04:33,530 --> 01:04:35,180 go ahead and book that flight. 1339 01:04:35,180 --> 01:04:38,720 And now, when I go to the Flights list, when I click Paris to New York, 1340 01:04:38,720 --> 01:04:42,840 that is going to access that passenger's property of the flight that we created. 1341 01:04:42,840 --> 01:04:46,660 And now, I see my three passengers listed in my passenger list. 1342 01:04:46,660 --> 01:04:48,410 And that was all because that relationship 1343 01:04:48,410 --> 01:04:49,826 allowed us to simplify the syntax. 1344 01:04:49,826 --> 01:04:52,460 So ultimately, what SQLAlchemy is going to be valuable 1345 01:04:52,460 --> 01:04:55,619 for is making it easier to do more complicated things with your database. 1346 01:04:55,619 --> 01:04:58,160 You're probably finding, as you're working through project 1, 1347 01:04:58,160 --> 01:05:01,700 that there's a lot of queries involved, a lot of selecting, a lot of making 1348 01:05:01,700 --> 01:05:04,280 sure you're selecting where certain conditions are true, 1349 01:05:04,280 --> 01:05:07,910 a lot of looking at relationships between different tables potentially. 1350 01:05:07,910 --> 01:05:11,330 And what SQLAlchemy is good at is making it easier 1351 01:05:11,330 --> 01:05:14,810 to relate those tables together, making it easier to extract information 1352 01:05:14,810 --> 01:05:16,880 from related tables and so forth. 1353 01:05:16,880 --> 01:05:20,692 Questions about any of that so far? 1354 01:05:20,692 --> 01:05:21,900 OK, we'll take a short break. 1355 01:05:21,900 --> 01:05:25,580 And when we come back, we'll dive into taking a look at APIs. 1356 01:05:25,580 --> 01:05:26,837 OK, welcome back. 1357 01:05:26,837 --> 01:05:29,420 I thought we'd wrap up our discussion about ORMs and then dive 1358 01:05:29,420 --> 01:05:32,660 into talking about APIs and how to use them and how to build them. 1359 01:05:32,660 --> 01:05:34,910 But I just want to do a quick wrap-up on relationships 1360 01:05:34,910 --> 01:05:36,743 and what that, ultimately, is going to mean, 1361 01:05:36,743 --> 01:05:39,620 in terms of how you can make your syntax a little bit easier. 1362 01:05:39,620 --> 01:05:43,340 And so, recall that before, when we had syntax like Select star from 1363 01:05:43,340 --> 01:05:47,930 passengers, where flight ID equals 1, if we have a particular flight, 1364 01:05:47,930 --> 01:05:51,050 like flight.query.get(1), using relationships now-- 1365 01:05:51,050 --> 01:05:54,740 using that passenger as property that we've added to our Flight class-- 1366 01:05:54,740 --> 01:05:57,410 we can now get at those individual passengers just by saying 1367 01:05:57,410 --> 01:06:01,730 flight.query.get(1).passengers to simplify the process of extracting 1368 01:06:01,730 --> 01:06:02,572 the passengers. 1369 01:06:02,572 --> 01:06:04,280 And that becomes all the more compelling, 1370 01:06:04,280 --> 01:06:05,904 if you look at syntax like this, right? 1371 01:06:05,904 --> 01:06:11,960 This was if I wanted to select Select star from flights join passengers 1372 01:06:11,960 --> 01:06:14,930 on flights that ID equals passengers.flight_id where 1373 01:06:14,930 --> 01:06:19,280 passengers.name equals Alice, where I'm joining the flights and passengers 1374 01:06:19,280 --> 01:06:21,960 together, getting Alice-- 1375 01:06:21,960 --> 01:06:23,840 wherever Alice's name is in the passengers-- 1376 01:06:23,840 --> 01:06:26,880 and getting whatever flight that Alice is on, for example. 1377 01:06:26,880 --> 01:06:29,210 If I wanted to simplify that query using SQLAlchemy, 1378 01:06:29,210 --> 01:06:30,780 it might look something like this-- 1379 01:06:30,780 --> 01:06:33,470 passenger.query.filter_by(name=Alice). 1380 01:06:33,470 --> 01:06:36,950 This first line is just saying, query my Passengers table. 1381 01:06:36,950 --> 01:06:40,370 Get me a passenger whose name is Alice. 1382 01:06:40,370 --> 01:06:43,430 And just get the first one, assuming there's only one Alice in our table. 1383 01:06:43,430 --> 01:06:46,880 And then .flight will get me all of that flight information such that I can then 1384 01:06:46,880 --> 01:06:50,480 access wherever Alice is coming from, where she's going to, and how long her 1385 01:06:50,480 --> 01:06:51,052 flight is. 1386 01:06:51,052 --> 01:06:52,760 And so these relationships can definitely 1387 01:06:52,760 --> 01:06:58,020 help to simplify that process, using the technology built into ORMs. 1388 01:06:58,020 --> 01:07:01,380 Just to answer a question a couple of people have given me-- 1389 01:07:01,380 --> 01:07:03,290 for project 1, the one about the books, we're 1390 01:07:03,290 --> 01:07:06,260 going to ask you actually not to use the ORM-like syntax 1391 01:07:06,260 --> 01:07:07,940 and just to stick to using the raw SQL. 1392 01:07:07,940 --> 01:07:11,150 Because there's a lot of value in understanding these Select and Insert 1393 01:07:11,150 --> 01:07:13,240 and Update queries and being able to use them. 1394 01:07:13,240 --> 01:07:15,260 But from here on out, starting in project 2 and going 1395 01:07:15,260 --> 01:07:17,134 forward, if we're interacting with databases, 1396 01:07:17,134 --> 01:07:20,060 feel free to use this syntax as well, because it can often 1397 01:07:20,060 --> 01:07:23,270 be more concise, more efficient, to be able to interact 1398 01:07:23,270 --> 01:07:26,420 with classes in the way that we have been in the examples 1399 01:07:26,420 --> 01:07:28,410 that we've been looking at so far. 1400 01:07:28,410 --> 01:07:30,410 But now, I wanted to take a moment to transition 1401 01:07:30,410 --> 01:07:33,710 to talking about our next topic, which is going to be APIs or Application 1402 01:07:33,710 --> 01:07:37,430 Programming Interfaces, which you can think of as, effectively, protocols 1403 01:07:37,430 --> 01:07:41,030 for communication between either different web applications 1404 01:07:41,030 --> 01:07:43,079 or different parts of the same web application, 1405 01:07:43,079 --> 01:07:46,370 where oftentimes different components of applications or different applications 1406 01:07:46,370 --> 01:07:50,520 altogether will want to be able to share information with each other 1407 01:07:50,520 --> 01:07:54,290 or will want to be able to perform actions in other spaces. 1408 01:07:54,290 --> 01:07:59,030 And APIs offer us a way to allow different components of web 1409 01:07:59,030 --> 01:08:02,160 applications to be able to communicate with each other. 1410 01:08:02,160 --> 01:08:05,210 And so, in order to do this, we will often 1411 01:08:05,210 --> 01:08:10,700 want to have a standard language for how different parts of our web application 1412 01:08:10,700 --> 01:08:12,630 will communicate with each other. 1413 01:08:12,630 --> 01:08:15,620 And so, in particular, the language we're going to look at here 1414 01:08:15,620 --> 01:08:18,979 is called JSON, or JavaScript Object Notation, which 1415 01:08:18,979 --> 01:08:22,790 is just a simple way of representing information 1416 01:08:22,790 --> 01:08:27,620 in a way that is both human readable and computer readable, such that it will be 1417 01:08:27,620 --> 01:08:32,750 easy to use JSON information to pass data from one part of one application 1418 01:08:32,750 --> 01:08:35,390 to another part of another application, for example. 1419 01:08:35,390 --> 01:08:40,069 So if I wanted to represent information about a particular flight, 1420 01:08:40,069 --> 01:08:43,761 using JSON notation, it might look something like this. 1421 01:08:43,761 --> 01:08:46,010 We've wrapped it in curly braces to enclose everything 1422 01:08:46,010 --> 01:08:48,080 in what's called a JSON object. 1423 01:08:48,080 --> 01:08:52,250 And I have divided the contents of this JSON object 1424 01:08:52,250 --> 01:08:54,450 into what are called Key Value pairs. 1425 01:08:54,450 --> 01:08:56,930 So I'm defining information about this flight 1426 01:08:56,930 --> 01:08:58,850 by specifying what its origin is. 1427 01:08:58,850 --> 01:09:00,770 The origin is Tokyo. 1428 01:09:00,770 --> 01:09:02,330 The destination is Shanghai. 1429 01:09:02,330 --> 01:09:04,470 And the duration is 185. 1430 01:09:04,470 --> 01:09:08,390 So this sort of notation is easy for us to read. 1431 01:09:08,390 --> 01:09:11,479 But in particular, it's also easy for a computer to read. 1432 01:09:11,479 --> 01:09:14,450 And why is that important? 1433 01:09:14,450 --> 01:09:16,970 What might we then want to do with an object like this? 1434 01:09:16,970 --> 01:09:19,479 Any ideas? 1435 01:09:19,479 --> 01:09:19,979 Yeah? 1436 01:09:19,979 --> 01:09:21,910 AUDIENCE: You could render it in your browser [INAUDIBLE].. 1437 01:09:21,910 --> 01:09:24,159 BRIAN YU: You could render it under browser-- exactly. 1438 01:09:24,159 --> 01:09:27,520 So other web applications, if they are able to receive data in this format, 1439 01:09:27,520 --> 01:09:31,000 in some standardized format, where they know to expect a JSON object that 1440 01:09:31,000 --> 01:09:33,460 will have an origin and a destination and duration, 1441 01:09:33,460 --> 01:09:36,729 those applications can take that data and do something meaningful or useful 1442 01:09:36,729 --> 01:09:40,359 with it-- extracts the origin and display the origin in a browser, 1443 01:09:40,359 --> 01:09:46,779 or do other useful tasks, using the data that's provided to us in JSON. 1444 01:09:46,779 --> 01:09:53,050 And JSON also supports the ability to nest within it other containers 1445 01:09:53,050 --> 01:09:54,770 or collections of other items. 1446 01:09:54,770 --> 01:09:58,810 So maybe, in our JSON object for representing what a flight is, 1447 01:09:58,810 --> 01:10:01,570 we might also want to represent the passengers in the flight 1448 01:10:01,570 --> 01:10:02,612 and who is on the flight. 1449 01:10:02,612 --> 01:10:04,361 And so that might look something like this 1450 01:10:04,361 --> 01:10:07,450 where, in addition to having an origin and a destination and duration, 1451 01:10:07,450 --> 01:10:12,760 I also have this list of passengers that has a name Alice and a name Bob 1452 01:10:12,760 --> 01:10:16,510 inside of a list, so that now, when I try and get 1453 01:10:16,510 --> 01:10:19,330 information about the flight, if my Application Programming 1454 01:10:19,330 --> 01:10:23,230 Interface, my API, gives back a JSON object that looks something like this, 1455 01:10:23,230 --> 01:10:26,110 now whatever computer is receiving that information 1456 01:10:26,110 --> 01:10:29,140 can process this list of passengers. 1457 01:10:29,140 --> 01:10:32,360 What if I wanted to add more sophisticated information? 1458 01:10:32,360 --> 01:10:36,850 What if I wanted to, in addition to having the origin being Tokyo, 1459 01:10:36,850 --> 01:10:39,430 I want to also specify, OK, the origin is Tokyo, 1460 01:10:39,430 --> 01:10:41,650 but I also want to give you that three-letter airline 1461 01:10:41,650 --> 01:10:44,570 code that corresponds to this particular Tokyo airport? 1462 01:10:44,570 --> 01:10:47,920 What might be a good way to do that, using JSON? 1463 01:10:47,920 --> 01:10:50,980 Using this notation of trying to represent information 1464 01:10:50,980 --> 01:10:52,590 using keys and values like this? 1465 01:10:52,590 --> 01:10:57,900 1466 01:10:57,900 --> 01:11:00,974 What would be a way to represent that information if I wanted to, 1467 01:11:00,974 --> 01:11:03,140 in addition to this information, include information 1468 01:11:03,140 --> 01:11:07,300 about Tokyo's airline airport code and Shanghai's airport code? 1469 01:11:07,300 --> 01:11:13,120 1470 01:11:13,120 --> 01:11:19,451 AUDIENCE: You could have two more key value pairs. 1471 01:11:19,451 --> 01:11:20,450 BRIAN YU: Yeah, exactly. 1472 01:11:20,450 --> 01:11:22,116 You could have two more key value pairs. 1473 01:11:22,116 --> 01:11:26,810 I could add in origin, airport code key that is whatever Tokyo's airport 1474 01:11:26,810 --> 01:11:29,336 code is, and a destination airport code that 1475 01:11:29,336 --> 01:11:31,460 is going to be whatever Shanghai's airport code is. 1476 01:11:31,460 --> 01:11:32,710 And that would certainly work. 1477 01:11:32,710 --> 01:11:36,024 And it would be a way to represent information in JSON format. 1478 01:11:36,024 --> 01:11:37,940 And if I was communicating with an application 1479 01:11:37,940 --> 01:11:40,850 and I knew that that was going to be the format that it would be in, 1480 01:11:40,850 --> 01:11:44,750 then I would be able to extract that information out of the application. 1481 01:11:44,750 --> 01:11:47,690 But one common paradigm you'll see in JSON notation 1482 01:11:47,690 --> 01:11:50,110 is the idea of actually taking these objects 1483 01:11:50,110 --> 01:11:52,110 and nesting them within each other, just to give 1484 01:11:52,110 --> 01:11:55,820 some sort of organization and hierarchy to the way this data is structured. 1485 01:11:55,820 --> 01:11:57,900 And so you might see something that looks something more like this, 1486 01:11:57,900 --> 01:11:59,520 which looks a little more complicated. 1487 01:11:59,520 --> 01:12:02,510 But really, all this is is the origin, now, 1488 01:12:02,510 --> 01:12:07,100 is itself a JSON object that contains a city and a code. 1489 01:12:07,100 --> 01:12:10,400 And likewise, the destination is itself a JSON object 1490 01:12:10,400 --> 01:12:12,080 that contains a city and a code. 1491 01:12:12,080 --> 01:12:13,670 The duration is still an integer. 1492 01:12:13,670 --> 01:12:16,730 The Passengers list is still a list of names. 1493 01:12:16,730 --> 01:12:20,140 And so, by nesting information in JSON objects 1494 01:12:20,140 --> 01:12:23,270 as the values of other keys inside of my JSON object, 1495 01:12:23,270 --> 01:12:25,690 you can begin to represent more complex-- 1496 01:12:25,690 --> 01:12:29,060 more sophisticated information in a really organized way. 1497 01:12:29,060 --> 01:12:32,150 And now, this becomes easy for a computer to be able to read. 1498 01:12:32,150 --> 01:12:34,550 Because if the computer wants to get at, what 1499 01:12:34,550 --> 01:12:38,300 is the airport code of the destination of this flight, it just needs to know, 1500 01:12:38,300 --> 01:12:39,692 go to the destination. 1501 01:12:39,692 --> 01:12:41,150 And inside of that, go to the code. 1502 01:12:41,150 --> 01:12:44,180 And likewise, for the origin, go to the origin and then go to the code. 1503 01:12:44,180 --> 01:12:48,080 And you'll find that programming languages like Python and JavaScript 1504 01:12:48,080 --> 01:12:50,720 have very easy ways of interacting with objects like this 1505 01:12:50,720 --> 01:12:54,410 and extracting out information-- extracting the values from this object 1506 01:12:54,410 --> 01:12:57,020 in a way that's useful and meaningful. 1507 01:12:57,020 --> 01:12:58,470 So how are we going to do that? 1508 01:12:58,470 --> 01:13:02,420 How are we going to take our web application's API and interact 1509 01:13:02,420 --> 01:13:05,300 with, either, our own web application API or some other one that 1510 01:13:05,300 --> 01:13:07,790 exists elsewhere on the internet? 1511 01:13:07,790 --> 01:13:11,030 Well, oftentimes, it's going to happen through the URL 1512 01:13:11,030 --> 01:13:13,670 where, inside the URL of the web page, we're 1513 01:13:13,670 --> 01:13:18,270 going to specify what particular information we want to access. 1514 01:13:18,270 --> 01:13:24,350 So for instance-- these should be flights-- 1515 01:13:24,350 --> 01:13:30,290 going to /flights, for instance, would give you a listing, in the API format, 1516 01:13:30,290 --> 01:13:32,090 of all of the flights, for instance. 1517 01:13:32,090 --> 01:13:38,360 And going to /flight/28, would give you an API JSON response of information 1518 01:13:38,360 --> 01:13:40,310 about the flight with ID number 28. 1519 01:13:40,310 --> 01:13:43,550 And if I wanted to get at the passengers on flight 28, 1520 01:13:43,550 --> 01:13:47,780 I might go to /flight/28/passengers to get the information about those 1521 01:13:47,780 --> 01:13:48,680 passengers. 1522 01:13:48,680 --> 01:13:51,710 And likewise, if I knew that a particular passenger had ID number 6 1523 01:13:51,710 --> 01:13:55,220 and I wanted to get back a JSON object with information about them, 1524 01:13:55,220 --> 01:13:59,270 I might go to /flight/28/passengers/6. 1525 01:13:59,270 --> 01:14:03,470 And this URL syntax might vary from one application to another. 1526 01:14:03,470 --> 01:14:07,160 But it's fairly conventional to use this nested URL structure 1527 01:14:07,160 --> 01:14:09,920 to describe different endpoints, so to speak, 1528 01:14:09,920 --> 01:14:12,170 different URLs that you can access in order 1529 01:14:12,170 --> 01:14:16,160 to get at particular types of information inside of the API. 1530 01:14:16,160 --> 01:14:19,520 So questions about any of that so far, before we 1531 01:14:19,520 --> 01:14:22,010 move on to some of the more implementation 1532 01:14:22,010 --> 01:14:24,670 details of how these things work? 1533 01:14:24,670 --> 01:14:27,810 And we'll see an example of this also. 1534 01:14:27,810 --> 01:14:31,390 OK, one other useful thing to note is that, when dealing with APIs, 1535 01:14:31,390 --> 01:14:34,100 we'll often want to do different things with our API. 1536 01:14:34,100 --> 01:14:37,310 Maybe we want to have a way in our API to say, 1537 01:14:37,310 --> 01:14:40,100 get me information about passenger number 28-- 1538 01:14:40,100 --> 01:14:41,810 so just extracting information. 1539 01:14:41,810 --> 01:14:43,910 We might also want a way to say, by an API, 1540 01:14:43,910 --> 01:14:48,140 I want to register a new passenger for a particular flight 1541 01:14:48,140 --> 01:14:50,180 such that, instead of needing to go to a website 1542 01:14:50,180 --> 01:14:53,480 and type in a name and a flight, I could just programmatically, 1543 01:14:53,480 --> 01:14:56,450 using a Python program, register for a flight 1544 01:14:56,450 --> 01:15:00,260 by using a flight's API that we would build out, for instance. 1545 01:15:00,260 --> 01:15:04,674 And so, maybe, I want to add information using the API as well. 1546 01:15:04,674 --> 01:15:06,590 I might also want to update information, like, 1547 01:15:06,590 --> 01:15:09,630 maybe if I want to change my registration information for a flight. 1548 01:15:09,630 --> 01:15:13,160 And so, oftentimes when dealing with APIs, 1549 01:15:13,160 --> 01:15:18,200 the HTTP request method that we use will correspond to the type of action 1550 01:15:18,200 --> 01:15:19,250 that we want to perform. 1551 01:15:19,250 --> 01:15:21,417 And this is just a convention that many APIs follow. 1552 01:15:21,417 --> 01:15:23,416 It's not that this is the only way to do things. 1553 01:15:23,416 --> 01:15:26,570 It's just that this happens to be a particularly common conventional way. 1554 01:15:26,570 --> 01:15:29,420 We've already seen Get and Post requests before, 1555 01:15:29,420 --> 01:15:32,780 in the context of Flask applications, where usually a Get request means, 1556 01:15:32,780 --> 01:15:35,090 I want to access a page, and a Post request 1557 01:15:35,090 --> 01:15:37,850 was when I was submitting data to a page. 1558 01:15:37,850 --> 01:15:41,000 These are some common HTTP requests methods that are frequently 1559 01:15:41,000 --> 01:15:43,310 used when dealing with APIs. 1560 01:15:43,310 --> 01:15:45,980 Get is usually the request method we use when 1561 01:15:45,980 --> 01:15:49,437 we want to retrieve a resource, where a resources is just 1562 01:15:49,437 --> 01:15:51,770 information about a flight, for instance, or information 1563 01:15:51,770 --> 01:15:52,910 about a passenger. 1564 01:15:52,910 --> 01:15:54,800 Post is typically the request method we use 1565 01:15:54,800 --> 01:15:57,680 when we want to create a new resource, register for a new flight, 1566 01:15:57,680 --> 01:15:59,510 create a new passenger. 1567 01:15:59,510 --> 01:16:01,940 Put is generally if we want to replace a resource. 1568 01:16:01,940 --> 01:16:04,430 Patch-- for updating an existing resource. 1569 01:16:04,430 --> 01:16:06,560 And Delete-- for deleting a resource. 1570 01:16:06,560 --> 01:16:10,580 And these are all just different HTTP request methods, different ways 1571 01:16:10,580 --> 01:16:14,420 of making requests to some web server. 1572 01:16:14,420 --> 01:16:17,870 So how do you actually make those requests programmatically? 1573 01:16:17,870 --> 01:16:22,400 We have been able to make Get requests already just by going to a browser. 1574 01:16:22,400 --> 01:16:25,530 Any time you go to a browser, type in a URL, and press Return, 1575 01:16:25,530 --> 01:16:27,800 you are making a Get request to that website. 1576 01:16:27,800 --> 01:16:30,230 But how do we do that in a program? 1577 01:16:30,230 --> 01:16:31,526 Inside of Python, for example? 1578 01:16:31,526 --> 01:16:33,650 Well, to do that, we'll take advantage of a library 1579 01:16:33,650 --> 01:16:36,117 in Python known as the Requests library. 1580 01:16:36,117 --> 01:16:39,200 And what the Requests library does-- this is the library written in Python 1581 01:16:39,200 --> 01:16:43,370 that will make it easy for us to make all of these various different HTTP 1582 01:16:43,370 --> 01:16:46,190 requests to different web servers. 1583 01:16:46,190 --> 01:16:51,890 So let's take a look at the Requests library in action. 1584 01:16:51,890 --> 01:16:55,750 So we'll first take a look at Google.py. 1585 01:16:55,750 --> 01:17:00,110 And so this is just a very simple program that is going to-- 1586 01:17:00,110 --> 01:17:04,340 after we've imported the Requests module into Python-- 1587 01:17:04,340 --> 01:17:08,120 inside the main function, say res-- which just stands for response. 1588 01:17:08,120 --> 01:17:12,860 Our response is going to be a variable equal to request.get. 1589 01:17:12,860 --> 01:17:17,420 Requests.get is a function that is going to take, as its input, a URL-- 1590 01:17:17,420 --> 01:17:18,430 just some URL. 1591 01:17:18,430 --> 01:17:20,930 It's going to make a Get request to that URL 1592 01:17:20,930 --> 01:17:23,910 and then get me back the HTTP response. 1593 01:17:23,910 --> 01:17:26,390 So effectively, think of this as Python's equivalent 1594 01:17:26,390 --> 01:17:32,330 of typing in HTTPS://google.com, pressing Return, and giving you back 1595 01:17:32,330 --> 01:17:33,710 whatever that response is. 1596 01:17:33,710 --> 01:17:36,890 So that response is saved in a variable called res-- a response. 1597 01:17:36,890 --> 01:17:39,660 And we're printing out response.text-- 1598 01:17:39,660 --> 01:17:43,640 so just the text of whatever came back from making a Get request 1599 01:17:43,640 --> 01:17:44,930 to google.com. 1600 01:17:44,930 --> 01:17:47,700 What do we think that's going to look like? 1601 01:17:47,700 --> 01:17:49,700 What's going to happen when we run this program? 1602 01:17:49,700 --> 01:17:51,191 What will we see? 1603 01:17:51,191 --> 01:17:51,690 Yeah? 1604 01:17:51,690 --> 01:17:54,379 AUDIENCE: I think you would see exactly what was on Google.com. 1605 01:17:54,379 --> 01:17:56,670 BRIAN YU: Yeah, we'll see exactly what's on google.com. 1606 01:17:56,670 --> 01:18:00,570 In particular, we'll see whatever we would get back 1607 01:18:00,570 --> 01:18:03,150 when we make a request to google.com. 1608 01:18:03,150 --> 01:18:06,120 Now of course, this doesn't look much like Google.come 1609 01:18:06,120 --> 01:18:07,260 as it sounds right now. 1610 01:18:07,260 --> 01:18:13,740 But this is just the HTML contents of whatever is on google.com. 1611 01:18:13,740 --> 01:18:16,994 And our web browsers, like Safari or Chrome, know how to take this HTML 1612 01:18:16,994 --> 01:18:18,160 and then actually render it. 1613 01:18:18,160 --> 01:18:22,000 So if we look around, we can probably find, like, a-- 1614 01:18:22,000 --> 01:18:22,500 yeah. 1615 01:18:22,500 --> 01:18:25,590 So here, somewhere in the HTML is the I'm Feeling Lucky button on Google. 1616 01:18:25,590 --> 01:18:29,160 And our web browsers know how to take all this information and render it. 1617 01:18:29,160 --> 01:18:33,480 So using just this code, we've been able to make a Get request 1618 01:18:33,480 --> 01:18:35,640 to a website-- in this case, google.com-- 1619 01:18:35,640 --> 01:18:38,400 and we've been able to print out the text of that response 1620 01:18:38,400 --> 01:18:43,720 by using response.text, to be able to access that information. 1621 01:18:43,720 --> 01:18:47,100 So how is that going to be useful to us? 1622 01:18:47,100 --> 01:18:50,280 Well, in particular, request.get is not the only request method 1623 01:18:50,280 --> 01:18:51,420 that we can use. 1624 01:18:51,420 --> 01:18:53,860 Just as we had request.get to make a Get request, 1625 01:18:53,860 --> 01:18:56,460 we can make all sorts of different HTTP requests 1626 01:18:56,460 --> 01:19:00,400 just by using the various functions that are built into the request module. 1627 01:19:00,400 --> 01:19:02,610 So we can do request.post to make a Post request; 1628 01:19:02,610 --> 01:19:06,150 request.put to make a Put request; and then a Patch request and a Delete 1629 01:19:06,150 --> 01:19:09,240 request respectively, so that all of those things we wanted to do with 1630 01:19:09,240 --> 01:19:10,080 APIs-- 1631 01:19:10,080 --> 01:19:12,900 if there's a way to do them using a particular request method, 1632 01:19:12,900 --> 01:19:17,250 there is a way to do that using requests in Python. 1633 01:19:17,250 --> 01:19:21,900 So let's try and use this to actually take advantage of an existing API 1634 01:19:21,900 --> 01:19:24,330 and do something interesting with it. 1635 01:19:24,330 --> 01:19:29,530 So one API will take a look at is going to be fixer.io. 1636 01:19:29,530 --> 01:19:32,220 This is a API that already exists elsewhere on the internet. 1637 01:19:32,220 --> 01:19:34,090 I had nothing to do with it. 1638 01:19:34,090 --> 01:19:37,350 And we're just going to try and use it to do something useful-- to write 1639 01:19:37,350 --> 01:19:39,150 a program that takes advantage of it. 1640 01:19:39,150 --> 01:19:42,240 What Fixer is is it's a foreign exchange rate API. 1641 01:19:42,240 --> 01:19:47,070 So it's going to, every day, have stored somewhere the latest exchange 1642 01:19:47,070 --> 01:19:48,390 rates for currency. 1643 01:19:48,390 --> 01:19:52,980 And it offers an API that makes it easy for us to access those exchange rates 1644 01:19:52,980 --> 01:19:56,860 and do something useful with it, in a format that's readable by a computer. 1645 01:19:56,860 --> 01:19:59,640 So if I were to read through this usage section, 1646 01:19:59,640 --> 01:20:04,860 I would notice that, in order to use this API, I have to go to API.fixer.io. 1647 01:20:04,860 --> 01:20:11,100 And then I could, say, specify a base currency and then other symbols. 1648 01:20:11,100 --> 01:20:20,010 So if I go to, for instance, API.fixer.io/latest?base=USD, 1649 01:20:20,010 --> 01:20:23,640 for US Dollars, &symbols=-- 1650 01:20:23,640 --> 01:20:26,170 we'll do GBP for British pounds. 1651 01:20:26,170 --> 01:20:29,220 And I'll press Return on that URL here. 1652 01:20:29,220 --> 01:20:30,840 So I'm going to that particular API. 1653 01:20:30,840 --> 01:20:33,404 And the only reason I know what to put in the URL 1654 01:20:33,404 --> 01:20:35,820 is because I looked at the documentation on the other page 1655 01:20:35,820 --> 01:20:39,690 to say, what should I put in the URL to get back the result that I want? 1656 01:20:39,690 --> 01:20:42,270 So if I type that into the URL and press Return, 1657 01:20:42,270 --> 01:20:45,390 then this is the response that I get back. 1658 01:20:45,390 --> 01:20:47,160 I get back, ultimately, a JSON object. 1659 01:20:47,160 --> 01:20:48,940 It's not formatted as prettily as the ones 1660 01:20:48,940 --> 01:20:50,650 that we saw in the slides a moment ago. 1661 01:20:50,650 --> 01:20:52,470 But it's just surrounded in curly braces. 1662 01:20:52,470 --> 01:20:54,150 And it's got a bunch of keys and values. 1663 01:20:54,150 --> 01:20:58,200 It's got the base, which is US dollars; the date that this was extracted on-- 1664 01:20:58,200 --> 01:21:02,070 February 26-- and then rates, which is, inside of it, 1665 01:21:02,070 --> 01:21:05,790 another JSON object that contains British pounds; 1666 01:21:05,790 --> 01:21:09,930 and then 0.71282, which is the current exchange rate 1667 01:21:09,930 --> 01:21:12,390 between US dollars and British pounds. 1668 01:21:12,390 --> 01:21:15,610 And so this is not super nice for a human to look at. 1669 01:21:15,610 --> 01:21:18,100 We can read it and parse out what the stuff means. 1670 01:21:18,100 --> 01:21:20,460 But because this is in JavaScript Object Notation-- 1671 01:21:20,460 --> 01:21:23,940 JSON-- format, this is now very easy for a computer then 1672 01:21:23,940 --> 01:21:26,290 to be able to understand and manipulate. 1673 01:21:26,290 --> 01:21:27,600 So what would that look like? 1674 01:21:27,600 --> 01:21:28,600 And how would that work? 1675 01:21:28,600 --> 01:21:30,750 How could we write a computer program in Python 1676 01:21:30,750 --> 01:21:33,750 to be able to take advantage of the fact that we have this API elsewhere 1677 01:21:33,750 --> 01:21:37,920 on the internet that gives us access to currency exchange rates? 1678 01:21:37,920 --> 01:21:42,420 Let's take a look now at currency0.py. 1679 01:21:42,420 --> 01:21:44,160 What's going on in here? 1680 01:21:44,160 --> 01:21:46,920 So inside of our main function, after we import request, 1681 01:21:46,920 --> 01:21:52,640 the first thing we do is call request.get and then this URL-- 1682 01:21:52,640 --> 01:21:54,960 api.fixer.io-- latest base is USD. 1683 01:21:54,960 --> 01:21:57,390 Symbol is the euro, in this case. 1684 01:21:57,390 --> 01:22:00,030 So basically, the same URL syntax that I used before. 1685 01:22:00,030 --> 01:22:04,140 Because I know now how fixer.io's API works. 1686 01:22:04,140 --> 01:22:09,720 And I'm saying, if the status code that came back from this request is not 200, 1687 01:22:09,720 --> 01:22:10,620 raise an exception. 1688 01:22:10,620 --> 01:22:13,980 Raising an exception in Python is, basically, a way in Python to say, 1689 01:22:13,980 --> 01:22:15,162 something bad happened. 1690 01:22:15,162 --> 01:22:15,870 Quit the program. 1691 01:22:15,870 --> 01:22:17,944 There should be some sort of error at this point. 1692 01:22:17,944 --> 01:22:20,860 And so I'm saying, Error, there was some problem with the API request, 1693 01:22:20,860 --> 01:22:23,310 if it didn't successfully return as 200. 1694 01:22:23,310 --> 01:22:29,610 But then, what's going on here on line 7, is I'm getting the response.json. 1695 01:22:29,610 --> 01:22:35,640 And this .json method is a way of taking the result of a request and extracting 1696 01:22:35,640 --> 01:22:38,580 that JSON data-- that JavaScript Object Notation data-- 1697 01:22:38,580 --> 01:22:41,070 and save it inside of a variable called Data. 1698 01:22:41,070 --> 01:22:43,510 And now, I'm going to print out that data. 1699 01:22:43,510 --> 01:22:48,430 So what's going to happen when I try and run this program? 1700 01:22:48,430 --> 01:22:52,320 I'm going to run Python currency0.py. 1701 01:22:52,320 --> 01:22:55,050 And when I get back, printed to my screen, 1702 01:22:55,050 --> 01:23:00,430 is that same JavaScript object that I saw in the web browser a moment ago, 1703 01:23:00,430 --> 01:23:03,210 except this time with euros, where I have the base currency as US 1704 01:23:03,210 --> 01:23:06,270 dollar, the date, and the currency exchange 1705 01:23:06,270 --> 01:23:09,450 rate between the dollar and the euro. 1706 01:23:09,450 --> 01:23:13,450 Questions about how that worked? 1707 01:23:13,450 --> 01:23:16,700 Before we move on, I'll do a brief note about status codes. 1708 01:23:16,700 --> 01:23:19,120 So we saw status code 200 just now, which 1709 01:23:19,120 --> 01:23:21,190 meant that everything worked out fine. 1710 01:23:21,190 --> 01:23:24,610 If the status code from an HTTP response is the number 200, 1711 01:23:24,610 --> 01:23:26,410 that generally means things are OK. 1712 01:23:26,410 --> 01:23:28,810 And every status code has a slightly different meaning. 1713 01:23:28,810 --> 01:23:32,320 And some common ones you'll see an APIs would be-- so 200 OK 1714 01:23:32,320 --> 01:23:34,539 just means the request was successful. 1715 01:23:34,539 --> 01:23:37,330 So very often, you'll see, when you're writing code that uses APIs, 1716 01:23:37,330 --> 01:23:39,940 you may want to check, was the response a 200? 1717 01:23:39,940 --> 01:23:42,220 And if it was, then probably all was fine. 1718 01:23:42,220 --> 01:23:45,780 But there are also other response codes that are used for various purposes. 1719 01:23:45,780 --> 01:23:50,170 201 is also a success-related response code 1720 01:23:50,170 --> 01:23:52,760 that generally means something was just created. 1721 01:23:52,760 --> 01:23:58,630 So if I made an API request to create a new passenger on a flight, 1722 01:23:58,630 --> 01:24:01,840 for instance, the response might conventionally be a 201, 1723 01:24:01,840 --> 01:24:05,240 meaning, that new passenger was created successfully. 1724 01:24:05,240 --> 01:24:09,480 So 2 in the hundredths place generally stands for a successful request. 1725 01:24:09,480 --> 01:24:12,770 And a 4 in the hundreds place generally stands for some sort of error. 1726 01:24:12,770 --> 01:24:15,019 400 generally means it was a bad request. 1727 01:24:15,019 --> 01:24:17,560 It was ill-formatted or there was something about the request 1728 01:24:17,560 --> 01:24:20,950 that you made that we couldn't really understand. 1729 01:24:20,950 --> 01:24:22,690 403 means forbidden. 1730 01:24:22,690 --> 01:24:25,166 If you're trying to access a resource that, 1731 01:24:25,166 --> 01:24:27,040 maybe, you need special permission to access. 1732 01:24:27,040 --> 01:24:29,110 You need to be logged in or something to access. 1733 01:24:29,110 --> 01:24:30,070 You might get that. 1734 01:24:30,070 --> 01:24:32,140 404 Not Found-- it's frequently happening 1735 01:24:32,140 --> 01:24:35,330 whenever you make an API request for something that doesn't exist. 1736 01:24:35,330 --> 01:24:39,160 So if I request flight number 28, but I only have 25 flights in my database, 1737 01:24:39,160 --> 01:24:40,510 well there is no flight 28. 1738 01:24:40,510 --> 01:24:44,140 And so I'll very frequently get a 404 response from that. 1739 01:24:44,140 --> 01:24:46,300 405-- method not allowed. 1740 01:24:46,300 --> 01:24:49,812 Any ideas what that one might be? 1741 01:24:49,812 --> 01:24:51,270 AUDIENCE: Get and Post [INAUDIBLE]. 1742 01:24:51,270 --> 01:24:54,145 BRIAN YU: Yeah, so Get and Post were the ideas of the request methods 1743 01:24:54,145 --> 01:24:54,880 we had before. 1744 01:24:54,880 --> 01:24:58,770 And so, if I have an API route that only accepts Get requests, 1745 01:24:58,770 --> 01:25:01,740 for instance, if I try and make a Post request to it, 1746 01:25:01,740 --> 01:25:04,260 I might very well get a 405 error, Method not Allowed. 1747 01:25:04,260 --> 01:25:07,290 Because you can't make a Post request if the API is only accepting 1748 01:25:07,290 --> 01:25:09,180 Get requests, for instance. 1749 01:25:09,180 --> 01:25:13,240 And 422, Unprocessable Entity is slightly less common, 1750 01:25:13,240 --> 01:25:19,080 but is often used if there is something about the API request 1751 01:25:19,080 --> 01:25:21,510 that we were able to understand the API request, 1752 01:25:21,510 --> 01:25:24,000 but you still had a bad request in some way. 1753 01:25:24,000 --> 01:25:26,040 Maybe in the currency example, for instance, 1754 01:25:26,040 --> 01:25:29,010 I requested a currency symbol that doesn't exist. 1755 01:25:29,010 --> 01:25:31,877 That might be an example of a time when I might get back a 422. 1756 01:25:31,877 --> 01:25:33,960 And there are other codes as well, but just wanted 1757 01:25:33,960 --> 01:25:37,020 to give you a sense for what common success and error codes actually 1758 01:25:37,020 --> 01:25:38,210 look like. 1759 01:25:38,210 --> 01:25:42,780 But going back now to the currency example 1760 01:25:42,780 --> 01:25:50,880 where we had this code that was going to print out the result of the API 1761 01:25:50,880 --> 01:25:54,990 request, and print out that data in JSON format, what could be 1762 01:25:54,990 --> 01:25:57,030 improved about this program right now? 1763 01:25:57,030 --> 01:26:00,840 Just from a user interface perspective, what's not so great about the fact that 1764 01:26:00,840 --> 01:26:05,320 I ran Python currency0.py and this is what comes back to me?-- 1765 01:26:05,320 --> 01:26:07,570 from the perspective of someone using the application. 1766 01:26:07,570 --> 01:26:08,500 Yeah? 1767 01:26:08,500 --> 01:26:13,059 AUDIENCE: You can parse out that information that printed line-by-line. 1768 01:26:13,059 --> 01:26:16,100 BRIAN YU: Yeah, the part the user really cares about is this part, right? 1769 01:26:16,100 --> 01:26:19,310 So this is the exchange rate that I want to display. 1770 01:26:19,310 --> 01:26:22,760 And it's sort of annoying for the user to have to look at this information 1771 01:26:22,760 --> 01:26:24,870 and understand what the keys and values are. 1772 01:26:24,870 --> 01:26:27,240 That really should be the job of the computer. 1773 01:26:27,240 --> 01:26:32,400 So let's take a look now at currency1.py and see how we did this. 1774 01:26:32,400 --> 01:26:36,600 And recall that this, right here, is what the response looks like. 1775 01:26:36,600 --> 01:26:41,180 So if we go into the rates key, we get back this object, 1776 01:26:41,180 --> 01:26:45,140 where the key of that object is the currency code, 1777 01:26:45,140 --> 01:26:49,500 and the value of that object is whatever the exchange rate actually is. 1778 01:26:49,500 --> 01:26:55,830 So what we can do now, inside of currency1.py, is do something similar. 1779 01:26:55,830 --> 01:26:59,090 Everything is the same up until this line where we extract the data in JSON 1780 01:26:59,090 --> 01:26:59,724 format. 1781 01:26:59,724 --> 01:27:02,890 But the nice thing about the JSON format is that it's very machine-readable. 1782 01:27:02,890 --> 01:27:06,230 It's very easy to tell a machine to access specific information 1783 01:27:06,230 --> 01:27:07,790 from that API response. 1784 01:27:07,790 --> 01:27:12,320 So I can now have a line like rate=data[rates-- 1785 01:27:12,320 --> 01:27:14,400 because rates was that key that I wanted. 1786 01:27:14,400 --> 01:27:16,760 And then the euro was the one that I wanted to look up. 1787 01:27:16,760 --> 01:27:18,980 Save that inside of a variable called Rate. 1788 01:27:18,980 --> 01:27:23,120 I was just extracting information from the JSON object in this line. 1789 01:27:23,120 --> 01:27:26,700 And now, on line 9, I can print out one, US dollar is equal to-- 1790 01:27:26,700 --> 01:27:27,980 plug-in the rate here-- 1791 01:27:27,980 --> 01:27:30,390 euros. 1792 01:27:30,390 --> 01:27:32,779 So now, when I run this program, rather than just see 1793 01:27:32,779 --> 01:27:34,820 that JSON object printed out to the screen, which 1794 01:27:34,820 --> 01:27:39,320 wasn't so great, I can run Python currency1.py and get, $1 US 1795 01:27:39,320 --> 01:27:41,499 is equal to 0.81169 euros. 1796 01:27:41,499 --> 01:27:44,540 And the great thing about this is that my program doesn't need to change. 1797 01:27:44,540 --> 01:27:46,430 Tomorrow, if I run this again, it's going 1798 01:27:46,430 --> 01:27:49,849 to be the new latest exchange rate for between the US dollar and the euro. 1799 01:27:49,849 --> 01:27:52,890 And I didn't need to worry about, how do you calculate the exchange rate? 1800 01:27:52,890 --> 01:27:55,190 Where are we getting the exchange rate's information from? 1801 01:27:55,190 --> 01:27:57,110 As it turns out, this API is getting that info 1802 01:27:57,110 --> 01:27:58,310 from the European Central Bank. 1803 01:27:58,310 --> 01:27:59,560 But I don't need to know that. 1804 01:27:59,560 --> 01:28:02,840 I just need to know what request to make in order to get at that information 1805 01:28:02,840 --> 01:28:04,424 and let the API handle the rest. 1806 01:28:04,424 --> 01:28:06,590 And then I can use that information and meaningfully 1807 01:28:06,590 --> 01:28:09,440 represent it in the output. 1808 01:28:09,440 --> 01:28:13,460 Questions about how that worked and how we're able to extract information out 1809 01:28:13,460 --> 01:28:15,262 of the JSON object just them? 1810 01:28:15,262 --> 01:28:18,118 AUDIENCE: I have a different question on this [INAUDIBLE].. 1811 01:28:18,118 --> 01:28:19,260 BRIAN YU: About the-- 1812 01:28:19,260 --> 01:28:22,536 AUDIENCE: About, like, how do I know that I'm going to [INAUDIBLE] out? 1813 01:28:22,536 --> 01:28:25,839 And how about HTML or XML objects? 1814 01:28:25,839 --> 01:28:26,880 BRIAN YU: Great question. 1815 01:28:26,880 --> 01:28:29,460 How do I know, is the question, that I'm going to get back 1816 01:28:29,460 --> 01:28:30,750 the JSON object as a response? 1817 01:28:30,750 --> 01:28:33,330 What if I just got back an HTML page, like we saw in Google, 1818 01:28:33,330 --> 01:28:36,840 or an XML, which is a different file format for representing data? 1819 01:28:36,840 --> 01:28:39,690 Ultimately, it depends upon the API's documentation. 1820 01:28:39,690 --> 01:28:42,630 So generally, when an API is made public on the internet, whoever 1821 01:28:42,630 --> 01:28:45,390 provided it will provide instructions for how to use it, 1822 01:28:45,390 --> 01:28:47,927 describing-- here are the routes you can access. 1823 01:28:47,927 --> 01:28:50,760 Here are the request methods you should use in order to access them, 1824 01:28:50,760 --> 01:28:52,830 like Get or Post or Put or Patch. 1825 01:28:52,830 --> 01:28:55,860 And they will also describe what the response looks like, 1826 01:28:55,860 --> 01:28:59,340 what the keys are in the response, so that you know, 1827 01:28:59,340 --> 01:29:01,110 is the response going to be a JSON format? 1828 01:29:01,110 --> 01:29:03,120 If it is, what are the keys and values? 1829 01:29:03,120 --> 01:29:06,390 And if you can reliably know that that API won't change, 1830 01:29:06,390 --> 01:29:08,320 then you're able to use that information. 1831 01:29:08,320 --> 01:29:11,700 So we only know that it's a JSON response because the website tells us 1832 01:29:11,700 --> 01:29:14,200 it's a JSON response and because we've experimented with it. 1833 01:29:14,200 --> 01:29:16,660 AUDIENCE: [INAUDIBLE] in order to support the XML, JSON, 1834 01:29:16,660 --> 01:29:17,640 and any other format? 1835 01:29:17,640 --> 01:29:21,560 Like, I am going to use the same quote, simple JAVA. 1836 01:29:21,560 --> 01:29:25,960 Site might be supporting JSON or XML or anything else. 1837 01:29:25,960 --> 01:29:26,460 And-- 1838 01:29:26,460 --> 01:29:27,120 BRIAN YU: Great question. 1839 01:29:27,120 --> 01:29:27,270 So-- 1840 01:29:27,270 --> 01:29:27,900 AUDIENCE: [INAUDIBLE] 1841 01:29:27,900 --> 01:29:28,525 BRIAN YU: Yeah. 1842 01:29:28,525 --> 01:29:31,230 So the question is, can the request modules 1843 01:29:31,230 --> 01:29:32,910 support things that are not JSON? 1844 01:29:32,910 --> 01:29:33,660 The answer is yes. 1845 01:29:33,660 --> 01:29:36,806 If you just use the .text, like we saw before, you can get the raw text. 1846 01:29:36,806 --> 01:29:38,430 And then you can parse that in any way. 1847 01:29:38,430 --> 01:29:42,030 And there are ways, in Python, to be able to parse XML strings, 1848 01:29:42,030 --> 01:29:44,990 for instance, and so on and so forth, with other file formats. 1849 01:29:44,990 --> 01:29:48,050 And so you can definitely do that as well. 1850 01:29:48,050 --> 01:29:49,800 Anyone have ideas for things we might want 1851 01:29:49,800 --> 01:29:52,380 to do to improve this currency converter program? 1852 01:29:52,380 --> 01:29:55,284 To make it a little more interesting and more useful? 1853 01:29:55,284 --> 01:29:57,080 AUDIENCE: Put it on a website. 1854 01:29:57,080 --> 01:29:58,360 BRIAN YU: You might want to put it on a website-- certainly. 1855 01:29:58,360 --> 01:30:00,910 And so, on a website, you would be able to do the same thing. 1856 01:30:00,910 --> 01:30:04,090 Using this Request library, if you were writing this in a Flask application, 1857 01:30:04,090 --> 01:30:07,060 we might be able to put it into a website, 1858 01:30:07,060 --> 01:30:10,810 allow you to type in a currency, type in the currency you want to convert it to, 1859 01:30:10,810 --> 01:30:11,800 and just convert it. 1860 01:30:11,800 --> 01:30:14,080 And that would allow us to do that conversion. 1861 01:30:14,080 --> 01:30:17,288 We'll take a look at a website in just a moment, when we make the return back 1862 01:30:17,288 --> 01:30:20,247 to our own Flights program. 1863 01:30:20,247 --> 01:30:23,080 For now, let's just do this on the Command line though, and look at, 1864 01:30:23,080 --> 01:30:27,190 how might we allow us to convert any two currencies, instead of just US 1865 01:30:27,190 --> 01:30:29,500 dollars and euros? 1866 01:30:29,500 --> 01:30:34,420 So let's take a look at currency2.py, which is a little more complicated 1867 01:30:34,420 --> 01:30:37,030 but, ultimately, is based on the same general ideas. 1868 01:30:37,030 --> 01:30:39,150 So the first thing we're doing here on line 4 1869 01:30:39,150 --> 01:30:40,770 is asking for input from the user. 1870 01:30:40,770 --> 01:30:42,330 Type in the first currency. 1871 01:30:42,330 --> 01:30:43,981 Save that as the base. 1872 01:30:43,981 --> 01:30:45,980 Type in the other currency, the second currency. 1873 01:30:45,980 --> 01:30:47,370 Save that as Other. 1874 01:30:47,370 --> 01:30:49,900 Then use request.get. 1875 01:30:49,900 --> 01:30:53,170 And in particular, I'm going to api.fixer.io/latest. 1876 01:30:53,170 --> 01:30:56,370 But this time, the base and symbol information 1877 01:30:56,370 --> 01:31:00,810 that I provided as arguments or parameters to the URL last time-- 1878 01:31:00,810 --> 01:31:02,950 I don't yet know what those are going to be. 1879 01:31:02,950 --> 01:31:05,730 And so, I'm adding this additional argument, Params, 1880 01:31:05,730 --> 01:31:09,720 to request.get, which lets me specify additional information 1881 01:31:09,720 --> 01:31:13,410 to parameterize this URL in the Get request-- to pass in the information 1882 01:31:13,410 --> 01:31:15,180 that I want to pass into the Get request. 1883 01:31:15,180 --> 01:31:17,750 And likewise, with request.post and a bunch of others, 1884 01:31:17,750 --> 01:31:20,190 you can pass in, like, a data attribute, to pass 1885 01:31:20,190 --> 01:31:22,470 in information data about that request. 1886 01:31:22,470 --> 01:31:26,940 But in this case, I'm saying, go to the fixer.io API. 1887 01:31:26,940 --> 01:31:31,560 Pass in the Base as the base currency and Other as the symbol 1888 01:31:31,560 --> 01:31:32,550 that I want to extract. 1889 01:31:32,550 --> 01:31:34,800 And I only know that these are called Base and Symbols 1890 01:31:34,800 --> 01:31:39,090 because, when I went to the API website, it told me, call your parameters base, 1891 01:31:39,090 --> 01:31:40,950 and call your parameters symbols. 1892 01:31:40,950 --> 01:31:42,290 I make that Get request. 1893 01:31:42,290 --> 01:31:45,330 If the status code response is not 200, raise the exception. 1894 01:31:45,330 --> 01:31:48,790 Then extract the JSON data on line 10. 1895 01:31:48,790 --> 01:31:53,730 On line 11, I want to go into that JSON object, extract the rates information. 1896 01:31:53,730 --> 01:31:57,280 And the name of the key is just going to be the name of that currency-- 1897 01:31:57,280 --> 01:32:00,360 so Other in this case, which is whatever the second currency was-- 1898 01:32:00,360 --> 01:32:03,600 and then print out one of this-- base currency 1899 01:32:03,600 --> 01:32:08,670 is equal to whatever the exchange rate is of the other currency, for instance. 1900 01:32:08,670 --> 01:32:11,940 And so now I can use this to begin to convert between any currencies. 1901 01:32:11,940 --> 01:32:18,660 If I run currency2.py and I type in US dollars as my first currency 1902 01:32:18,660 --> 01:32:21,870 and Japanese yen as my second currency, for example, 1903 01:32:21,870 --> 01:32:25,720 I get $1 US is equal to 106.82 Japanese yen. 1904 01:32:25,720 --> 01:32:29,460 And so I can start to build functionality on top of this API 1905 01:32:29,460 --> 01:32:33,480 and use APIs to enhance my own existing applications. 1906 01:32:33,480 --> 01:32:36,090 And that's ultimately what APIs are going to be useful for us 1907 01:32:36,090 --> 01:32:38,880 for in the upcoming project where, in project 1, 1908 01:32:38,880 --> 01:32:41,914 you'll use the API of a book review website to be able to say, 1909 01:32:41,914 --> 01:32:44,580 there are all these reviews for books out there on the internet. 1910 01:32:44,580 --> 01:32:47,536 Let's extract some of them and get that rating information 1911 01:32:47,536 --> 01:32:49,410 so that we can display it on our own website, 1912 01:32:49,410 --> 01:32:55,620 using APIs built by others in order to add to or enhance our own website. 1913 01:32:55,620 --> 01:33:01,690 Questions about how we can use APIs written by others? 1914 01:33:01,690 --> 01:33:04,410 OK, so what we'll move on to now is our final point, 1915 01:33:04,410 --> 01:33:07,500 which is going to be about how to design our own APIs. 1916 01:33:07,500 --> 01:33:11,970 So this might be useful, for instance, in our Airline application, 1917 01:33:11,970 --> 01:33:15,960 if we wanted to allow for ways for other people 1918 01:33:15,960 --> 01:33:20,540 to be able to write APIs that interacted with our Flight website. 1919 01:33:20,540 --> 01:33:23,640 Maybe you want to allow your Flight website 1920 01:33:23,640 --> 01:33:27,267 to be accessed by APIs so that other people can develop 1921 01:33:27,267 --> 01:33:29,850 phone applications that are able to talk to the Flight website 1922 01:33:29,850 --> 01:33:32,640 and extract information about flights or build other websites that 1923 01:33:32,640 --> 01:33:36,720 are able to talk to our website and get information about flight data. 1924 01:33:36,720 --> 01:33:40,200 And that's only possible if there exists some APIs, some protocol, that 1925 01:33:40,200 --> 01:33:43,320 allows for multiple different applications to talk to each other, 1926 01:33:43,320 --> 01:33:46,470 using some shared language, using some JSON object that follows 1927 01:33:46,470 --> 01:33:48,420 some predefined standard format. 1928 01:33:48,420 --> 01:33:52,410 So how might we go about doing that inside of our web application? 1929 01:33:52,410 --> 01:33:55,870 Well, let's take a look at an example. 1930 01:33:55,870 --> 01:33:59,676 So I'll go into Airline5. 1931 01:33:59,676 --> 01:34:01,800 And so, inside of application.py, this is very much 1932 01:34:01,800 --> 01:34:03,862 the same as what we've already seen before. 1933 01:34:03,862 --> 01:34:05,820 But the only difference that we're going to add 1934 01:34:05,820 --> 01:34:10,660 is we're going to add another route at the bottom of this file, which 1935 01:34:10,660 --> 01:34:13,080 I've just called Flight API for now. 1936 01:34:13,080 --> 01:34:15,600 And how is this working? 1937 01:34:15,600 --> 01:34:19,170 Well, this Flight API route inside of our application.py file inside 1938 01:34:19,170 --> 01:34:25,602 of our web application is going to be the route /api/flights/ some integer. 1939 01:34:25,602 --> 01:34:27,810 So I'm just going to build one API route for now that 1940 01:34:27,810 --> 01:34:31,350 is going to let us extract information about a particular flight. 1941 01:34:31,350 --> 01:34:35,910 In particular, if you go to the URL of my website, /api/flights/28, 1942 01:34:35,910 --> 01:34:39,000 for instance, you will get back information about flight number 28, 1943 01:34:39,000 --> 01:34:39,870 according to my API. 1944 01:34:39,870 --> 01:34:41,786 And I would probably document this if I wanted 1945 01:34:41,786 --> 01:34:44,980 to make it available to the public for them to be able to use. 1946 01:34:44,980 --> 01:34:49,530 So what happens when I go to this API route 1947 01:34:49,530 --> 01:34:52,592 and I pass in a particular flight ID? 1948 01:34:52,592 --> 01:34:54,300 Well, what might happen is, first, I want 1949 01:34:54,300 --> 01:34:56,040 to make sure the flight actually exists. 1950 01:34:56,040 --> 01:35:00,540 So flight=Flight.query.get(Flight_id), just trying to extract it from 1951 01:35:00,540 --> 01:35:03,180 the database using SQLAlchemy, like we saw before. 1952 01:35:03,180 --> 01:35:06,390 If Flight is None-- in other words, if there is no flight that got returned 1953 01:35:06,390 --> 01:35:08,130 from flight.query.get-- 1954 01:35:08,130 --> 01:35:13,140 what I'm going to return is a JavaScript Object Notation, JSON, 1955 01:35:13,140 --> 01:35:17,220 object that I'm going to wrap inside of this JSONify function. 1956 01:35:17,220 --> 01:35:20,600 And what this is going to do is take a Python dictionary, 1957 01:35:20,600 --> 01:35:24,720 the things surrounded in curly braces, and convert it into a JSON object 1958 01:35:24,720 --> 01:35:27,360 and put all the required HTTP headers on it 1959 01:35:27,360 --> 01:35:30,180 that will let it go back as a successful JSON response. 1960 01:35:30,180 --> 01:35:31,380 This is built into Flask. 1961 01:35:31,380 --> 01:35:35,250 You can do, from Flask, import JSONify, to import this function. 1962 01:35:35,250 --> 01:35:37,262 And that will allow you to do this thing. 1963 01:35:37,262 --> 01:35:39,720 And so what I'm going to do here is, if there is no flight, 1964 01:35:39,720 --> 01:35:43,680 I'm going to return a JSON object that says, Error is the key. 1965 01:35:43,680 --> 01:35:46,770 And the value of that key is just going to be Invalid Flight ID-- 1966 01:35:46,770 --> 01:35:48,660 some description of what went wrong. 1967 01:35:48,660 --> 01:35:52,210 And then, when I return it, I'm also going to-- as Flask lets me do-- 1968 01:35:52,210 --> 01:35:53,647 pass back an Error code. 1969 01:35:53,647 --> 01:35:56,730 We haven't done this before when we've returned things in our applications 1970 01:35:56,730 --> 01:35:58,860 because, by default, when Flask returns something, 1971 01:35:58,860 --> 01:36:02,340 it's just going to return status code 200, meaning everything was OK. 1972 01:36:02,340 --> 01:36:04,590 But if I want to pass back a different status code, 1973 01:36:04,590 --> 01:36:08,310 I can pass it back as just ,422, for instance. 1974 01:36:08,310 --> 01:36:10,740 And so here, we're passing back this object that says, 1975 01:36:10,740 --> 01:36:12,980 Error Invalid Flight ID, with status code 1976 01:36:12,980 --> 01:36:15,480 422, which means there was some problem with the response. 1977 01:36:15,480 --> 01:36:17,590 We understood it, but there wasn't anything there. 1978 01:36:17,590 --> 01:36:20,220 You might also pass back a 404, like, Not Found. 1979 01:36:20,220 --> 01:36:22,020 We couldn't find the flight. 1980 01:36:22,020 --> 01:36:24,450 So different APIs follow different conventions. 1981 01:36:24,450 --> 01:36:27,630 And it's just good to know, in the documentation for an API, 1982 01:36:27,630 --> 01:36:31,170 to understand what a particular API is doing. 1983 01:36:31,170 --> 01:36:34,200 So once the flight does exist, what can we actually do with it? 1984 01:36:34,200 --> 01:36:35,760 We can now get all the passengers. 1985 01:36:35,760 --> 01:36:38,820 Recall that, due to that relationship syntax that we saw in our classes 1986 01:36:38,820 --> 01:36:41,280 before, to get at the passengers for a flight, 1987 01:36:41,280 --> 01:36:43,740 we just need to do flight.passengers and save it 1988 01:36:43,740 --> 01:36:45,900 inside of a variable called Passengers. 1989 01:36:45,900 --> 01:36:48,090 And now, let's maintain a list of the names 1990 01:36:48,090 --> 01:36:51,360 of all the people inside of our flight. 1991 01:36:51,360 --> 01:36:54,510 We can loop over every passenger in my list of passengers 1992 01:36:54,510 --> 01:36:58,950 and add to this list of names whatever the passenger's name is. 1993 01:36:58,950 --> 01:37:02,460 And then, finally, at the bottom here, what we're going to do 1994 01:37:02,460 --> 01:37:09,150 is return another JSON object that has an origin, that has a destination, 1995 01:37:09,150 --> 01:37:12,524 has a duration, and a list of passengers. 1996 01:37:12,524 --> 01:37:14,940 And so, by doing this, and with no status code specified-- 1997 01:37:14,940 --> 01:37:16,710 that's, by default, just going to be 200-- 1998 01:37:16,710 --> 01:37:20,040 we have now built an API route that is going to return information 1999 01:37:20,040 --> 01:37:22,530 about a flight in JSON format, in a way that is now 2000 01:37:22,530 --> 01:37:25,950 machine-readable by some other person writing some other application that's 2001 01:37:25,950 --> 01:37:30,040 going to talk to or communicate with our own API. 2002 01:37:30,040 --> 01:37:31,010 So let's try it out. 2003 01:37:31,010 --> 01:37:33,300 And we'll do Flask run. 2004 01:37:33,300 --> 01:37:35,190 And we started up the application. 2005 01:37:35,190 --> 01:37:40,420 If I just go to my URL /flight/1, this is what that page looked like. 2006 01:37:40,420 --> 01:37:42,940 Recall, it just had details, origin, destination, duration, 2007 01:37:42,940 --> 01:37:44,340 and a list of passengers. 2008 01:37:44,340 --> 01:37:49,470 And technically, this has all the same information that my API had. 2009 01:37:49,470 --> 01:37:52,020 But why then might we still want an API? 2010 01:37:52,020 --> 01:37:54,661 Even if we already have this page that we already built before? 2011 01:37:54,661 --> 01:37:55,160 Yeah? 2012 01:37:55,160 --> 01:37:55,950 AUDIENCE: It's machine-readable. 2013 01:37:55,950 --> 01:37:57,700 BRIAN YU: It's machine-readable-- exactly. 2014 01:37:57,700 --> 01:38:00,120 This would be possible, but likely more difficult, 2015 01:38:00,120 --> 01:38:03,340 for a machine to be able to parse and extract the origin and the destination 2016 01:38:03,340 --> 01:38:04,810 and the list of passengers. 2017 01:38:04,810 --> 01:38:12,460 But if I go into the URL now and change /flight/1 to add just /api/flight/1, 2018 01:38:12,460 --> 01:38:15,160 because that was the route that I decided on before, 2019 01:38:15,160 --> 01:38:18,700 now what I get back is something that looks a little less aesthetically 2020 01:38:18,700 --> 01:38:22,880 pleasing to the human but definitely more machine-readable. 2021 01:38:22,880 --> 01:38:25,630 I have this JSON object that has the destination. 2022 01:38:25,630 --> 01:38:30,130 It has the duration, the origin, and a list of all of the passengers 2023 01:38:30,130 --> 01:38:31,610 that are on this flight. 2024 01:38:31,610 --> 01:38:33,980 And so I've now built this API route that I can use. 2025 01:38:33,980 --> 01:38:36,700 And if I go into Python, I can use the Request library 2026 01:38:36,700 --> 01:38:39,040 to be able to extract this data, for instance. 2027 01:38:39,040 --> 01:38:45,340 So if I just open up Python and say, import the Request library-- 2028 01:38:45,340 --> 01:38:53,650 and let's do response=request.get, this local URL /api/flight/1, 2029 01:38:53,650 --> 01:38:57,580 now I can do response.json. 2030 01:38:57,580 --> 01:39:02,750 And I get back this object that contains within it all the relevant information. 2031 01:39:02,750 --> 01:39:05,110 So if I save it inside of a variable called Data, 2032 01:39:05,110 --> 01:39:08,400 now I can do data, passengers. 2033 01:39:08,400 --> 01:39:11,890 And I get back a listing of all of the passengers that are on the flight. 2034 01:39:11,890 --> 01:39:16,240 Because this is in a machine-readable format, that becomes much easier. 2035 01:39:16,240 --> 01:39:23,142 If I try to access not flight/1 but flight/100 when there is no flight/100, 2036 01:39:23,142 --> 01:39:24,100 what's going to happen? 2037 01:39:24,100 --> 01:39:29,010 2038 01:39:29,010 --> 01:39:32,670 What I get back is this JSON object with Error, Invalid Flight ID, 2039 01:39:32,670 --> 01:39:39,300 which is exactly what I expected to happen, because inside of my API route, 2040 01:39:39,300 --> 01:39:41,160 when I had an application.py-- 2041 01:39:41,160 --> 01:39:44,230 2042 01:39:44,230 --> 01:39:46,280 just make sure the flight actually exists-- 2043 01:39:46,280 --> 01:39:49,620 if no flight got returned, I was returning this JSON object 2044 01:39:49,620 --> 01:39:51,260 that said Invalid Flight ID. 2045 01:39:51,260 --> 01:39:53,990 And so even this is still relatively machine-readable, 2046 01:39:53,990 --> 01:39:56,020 because if I want to extract the error message, 2047 01:39:56,020 --> 01:39:59,501 I just go inside the JSON object, get at what the error is. 2048 01:39:59,501 --> 01:40:02,000 And now I have a string that represents what the problem is, 2049 01:40:02,000 --> 01:40:03,738 what went wrong in that process. 2050 01:40:03,738 --> 01:40:04,237 Yep? 2051 01:40:04,237 --> 01:40:07,040 AUDIENCE: So you get the status code from that [INAUDIBLE]?? 2052 01:40:07,040 --> 01:40:08,804 BRIAN YU: Yep, I do, res.status_code. 2053 01:40:08,804 --> 01:40:11,220 And then I'll give him back the status code that came back 2054 01:40:11,220 --> 01:40:13,590 from that particular response. 2055 01:40:13,590 --> 01:40:15,971 Good question. 2056 01:40:15,971 --> 01:40:17,970 All right, so that was building out our own API. 2057 01:40:17,970 --> 01:40:20,420 And so one thing that you'll do, when you 2058 01:40:20,420 --> 01:40:24,500 move into working on your own project, is you'll build an API of your own, 2059 01:40:24,500 --> 01:40:27,620 some way for people to be able to access the rating data that people have 2060 01:40:27,620 --> 01:40:30,480 submitted into your own application. 2061 01:40:30,480 --> 01:40:33,110 And as APIs get more complicated, there are other things 2062 01:40:33,110 --> 01:40:34,443 that might get involved in well. 2063 01:40:34,443 --> 01:40:36,320 I'll just talk briefly about API keys. 2064 01:40:36,320 --> 01:40:40,266 You'll often see that, with larger APIs, you'll 2065 01:40:40,266 --> 01:40:41,890 want to do what's called Rate Limiting. 2066 01:40:41,890 --> 01:40:46,280 You don't want anyone just make as many requests as you want to an API, 2067 01:40:46,280 --> 01:40:48,505 because it might overload the API. 2068 01:40:48,505 --> 01:40:51,380 And it might make it harder for other people to be able to access it. 2069 01:40:51,380 --> 01:40:54,230 And so oftentimes, what will happen is that APIs 2070 01:40:54,230 --> 01:40:55,760 will restrict access to an API. 2071 01:40:55,760 --> 01:40:58,190 You'll have to first get an API key, which 2072 01:40:58,190 --> 01:41:00,290 will just be a long string typically. 2073 01:41:00,290 --> 01:41:02,540 And any time you make an API request, you'll 2074 01:41:02,540 --> 01:41:06,980 need to provide, in that API request, your API key to the API request. 2075 01:41:06,980 --> 01:41:10,370 So when you deal with project 1 and use the API for books, 2076 01:41:10,370 --> 01:41:14,000 you'll need to do something to this effect, in order to create an API key 2077 01:41:14,000 --> 01:41:15,870 and use it in order to make requests. 2078 01:41:15,870 --> 01:41:20,530 And this is often used just to track, what API routes are people going to? 2079 01:41:20,530 --> 01:41:21,800 Who's going to them? 2080 01:41:21,800 --> 01:41:23,870 And it also lets you limit people. 2081 01:41:23,870 --> 01:41:29,660 So if you want to say, nobody can make more than 100 API requests per hour, 2082 01:41:29,660 --> 01:41:32,270 then you can enforce a limit like that by just keeping track. 2083 01:41:32,270 --> 01:41:35,030 Every time you get a request from a particular API key, 2084 01:41:35,030 --> 01:41:38,570 you can make a tally inside of a database somewhere of, 2085 01:41:38,570 --> 01:41:40,100 they just made an API key usage. 2086 01:41:40,100 --> 01:41:43,580 And that's one that's been cut from their total allocation 2087 01:41:43,580 --> 01:41:44,660 for that particular hour. 2088 01:41:44,660 --> 01:41:46,460 You don't need to worry about that too much for this project. 2089 01:41:46,460 --> 01:41:49,380 No need to do any rate-limiting of your own in the API that you build. 2090 01:41:49,380 --> 01:41:52,130 But know that, as you go exploring other APIs that are out there-- 2091 01:41:52,130 --> 01:41:54,760 and there are APIs for so many things nowadays-- 2092 01:41:54,760 --> 01:41:56,930 that many of them will have API keys that you'll 2093 01:41:56,930 --> 01:42:01,400 need to first register for and then use when you go about making requests. 2094 01:42:01,400 --> 01:42:05,190 But questions about anything about APIs? 2095 01:42:05,190 --> 01:42:05,990 Or ORMs? 2096 01:42:05,990 --> 01:42:06,890 Or SQL, in general? 2097 01:42:06,890 --> 01:42:09,920 Or anything that we've talked about so far today? 2098 01:42:09,920 --> 01:42:11,044 Yeah? 2099 01:42:11,044 --> 01:42:15,914 AUDIENCE: In general, when do we use regular database and JSON? 2100 01:42:15,914 --> 01:42:19,389 It seems to me that they are pretty similar to different things. 2101 01:42:19,389 --> 01:42:20,430 BRIAN YU: Great question. 2102 01:42:20,430 --> 01:42:23,055 So the question is, when would you use the database, as opposed 2103 01:42:23,055 --> 01:42:25,072 to using JSON, this object notation that we saw? 2104 01:42:25,072 --> 01:42:26,780 Oftentimes, they'll go very hand-in-hand. 2105 01:42:26,780 --> 01:42:28,940 In our Flights example, for instance, we have 2106 01:42:28,940 --> 01:42:31,697 our database that has a Flights table and a Passengers table. 2107 01:42:31,697 --> 01:42:33,530 But we don't want to let anyone in the world 2108 01:42:33,530 --> 01:42:36,701 just access those tables directly, because they might delete things 2109 01:42:36,701 --> 01:42:39,450 that we don't want them to delete or look at sensitive information 2110 01:42:39,450 --> 01:42:40,700 we don't want them to look at. 2111 01:42:40,700 --> 01:42:45,500 And so oftentimes, access to the database is controlled through the API 2112 01:42:45,500 --> 01:42:48,650 so that, if you want to get information about flight number 1, 2113 01:42:48,650 --> 01:42:52,010 you can't just ask the database for information about flight number 1. 2114 01:42:52,010 --> 01:42:56,630 You use the API to say go to /api/flight/1. 2115 01:42:56,630 --> 01:42:59,960 And then you get back a JSON object representing the information 2116 01:42:59,960 --> 01:43:00,980 about flight number 1. 2117 01:43:00,980 --> 01:43:03,420 But that data ultimately came from the database. 2118 01:43:03,420 --> 01:43:06,200 It's just that the application stands in the way of making sure 2119 01:43:06,200 --> 01:43:09,260 that the person making the request is only getting access to the things 2120 01:43:09,260 --> 01:43:11,000 that we want them to be able to access. 2121 01:43:11,000 --> 01:43:14,000 And so, very often, JSON object data and our database 2122 01:43:14,000 --> 01:43:15,740 will go together very frequently. 2123 01:43:15,740 --> 01:43:18,669 And you'll see that as you work on project 1. 2124 01:43:18,669 --> 01:43:20,460 All right, so we'll wrap up here for today. 2125 01:43:20,460 --> 01:43:23,168 And next week, we'll dive into a brand new programming language-- 2126 01:43:23,168 --> 01:43:25,460 JavaScript-- and explore how we can use that to make 2127 01:43:25,460 --> 01:43:28,970 our front-end websites even more interactive and more interesting. 2128 01:43:28,970 --> 01:43:30,820 Thank you. 2129 01:43:30,820 --> 01:43:33,658