[User] Please transcribe this text

[Assistant] And then finally I'll add a duration field, which is an integer that also shouldn't be null.


[User] Please transcribe this text

[Assistant] I'll end with an end parenthesis and a semicolon, press return, and that executes that command on my database. I have now created a table called flights. And to verify this in SQLite, in the prompt I can type .tables and that will show me all of the tables that currently exist in my database. And it just so happens that I have a table called flights.


[User] Please transcribe this text

[Assistant] Of course, there's nothing inside this table, which I can verify by running select star from flights, meaning get all the data from the flights table. If I press return, alright, nothing happens. I don't see anything. There's no data that happens to be here.


[User] Please transcribe this text

[Assistant] But now I could say something like insert into flights, then I'll provide in parentheses the names of the columns. And on the slide a moment ago, I showed this on multiple lines. That was just for visual sake. These command can be entirely on one line if we would like it to. So I can say origin, destination, and duration, and then provide values. I can say let's add New York.


[User] Please transcribe this text

[Assistant] So I press type in that command, press return, that adds a new row to my flights table. And I can verify this by running select star from flights.


[User] Please transcribe this text

[Assistant] And I see that now I have this table whose ID is 1, that's the ID column, from New York to London, uh, with a duration of 415 minutes. And I could do this again and again, and I in advance prepared a couple of insert queries just to give us a little bit more data. Each of this is just a different insert query.


[User] Please transcribe this text

[Assistant] That's gonna add one new flight into our database. So I'll go ahead and copy those and then into the database I'll go ahead and paste in all these insert commands to insert a whole bunch of flights into this database.


[User] Please transcribe this text

[Assistant] And now if I run select star from flights, what I get is all of the flights. And this is not formatted particularly nicely. SQLite has some additional tricks if you'd like to format it a little nicer. So I can say go ahead and put this into columns mode and give me some headers yes. So header dot headers yes. And now if I select star from flights,


[User] Please transcribe this text

[Assistant] The data is organized a little more nicely where things are really into columns and their headers for each of the rows where I can see that alright, I kind of have a text based representation of what I was displaying graphically a moment ago that inside of my flights table, I have four columns and ID column, origin, destination and duration.


[User] Please transcribe this text

[Assistant] Each flight is just one of the rows that's inside of this table.


[User] Please transcribe this text

[Assistant] And now I can begin to run additional select queries if I want to do something like select star from flights where origin equals New York.


[User] Please transcribe this text

[Assistant] Well then instead of getting back all of the flights, I'm only going to get back the flights where the origin is New York. So I can very quickly filter down on this data, only getting the information that I actually care about taking a look.


[User] Please transcribe this text

[Assistant] And there are other ways of interacting with SQLite as well, but this SQLite prompt is a very direct way of just being able to write a query very quickly and see the results of that query.


[User] Please transcribe this text

[Assistant] So it turns out there are other types of queries we can run as well. So we'll take a look at some others. We don't just need to say where something equals something else. Other types of boolean expressions are allowed as well.


[User] Please transcribe this text

[Assistant] So I could say something like, select star from flights where duration is greater than 500.


[User] Please transcribe this text

[Assistant] Where the idea here is, alright, let's look at the duration column. It's an integer.


[User] Please transcribe this text

[Assistant] So we can do arithmetic expressions on these values. I can take a value and see is it greater than 500 or not. And when I do that, what I get back is all of the rows that have a duration that's greater than 500. So I can begin to query not just on whether one value equals another value, but also other types of comparisons as well.


[User] Please transcribe this text

[Assistant] And much as in Python, as when we had Boolean expressions in Python, I could join multiple Boolean expressions together using words like and and or. SQL has the same type of thing in its own query syntax too. I could say something like select star from flights where duration is greater than 500 and destination equals Paris.


[User] Please transcribe this text

[Assistant] And as you might logically intuit this means, this means get me all the flights that are going to Paris and that take longer than 500 minutes. And it turns out there's only one such row inside this table that satisfies both of those constraints.


[User] Please transcribe this text

[Assistant] Of course, instead of using and, I could have also used or to get a different query, where now I'm looking for all of the flights.


[User] Please transcribe this text

[Assistant] Longer than 15 minutes or longer than 500 minutes or the destination is Paris. So as long as either of those conditions are met, I'm going to get results back.


[User] Please transcribe this text

[Assistant] And so what I get back are some of the rows where the destination is Paris, some rows where the destination isn't Paris, but the duration is more than 500 minutes, and of course any row that satisfies both of these constraints, in particular flight ID number two, that gets resulted as well when I run this particular query on this table.


[User] Please transcribe this text

[Assistant] And there are other types of queries I can perform in addition to that. So I can say something like, select star from flights where origin is in, and then in parentheses, New York comma Lima.


[User] Please transcribe this text

[Assistant] To say, check if the origin is in this sequence of possible values, the sequence of New York and Lima, as long as it is one of those two, then I want for the results to come back, and so then you'll get back


[User] Please transcribe this text

[Assistant] Rows that have an origin of New York, rows that have an origin of Lima as well. So you can begin to construct more sophisticated queries that are able to check for whether an origin is in a list of possible values, or even if it matches a particular pattern.


[User] Please transcribe this text

[Assistant] That maybe you know that one of the columns looks a certain way or is formatted according to a particular structure, but you don't know exactly what the value is. I could run a query like select star from flights where origin not equals but where origin is like


[User] Please transcribe this text

[Assistant] And then in quotation marks I have a bit of a strange expression, %A%.


[User] Please transcribe this text

[Assistant] This percent, again, stands for a wild card. And this time the wild card is looking at the values of a particular column. In this case, the value of the origin column, meaning the percent stands for zero or more characters, no matter what those characters are. We're looking for some number of characters, maybe zero, maybe more, followed by an a.


[User] Please transcribe this text

[Assistant] Followed by some other number of characters, maybe zero, maybe more.


[User] Please transcribe this text

[Assistant] And ultimately what this query is going to do is look inside of the flights table and get back to me all of the results where there is an A in the origin. As long as there is an A in the origin column, doesn't matter if there are characters before it or characters after it, all of the rows that come back are going to be the rows that just so happen to have an A in it.


[User] Please transcribe this text

[Assistant] So lots of ways we can begin to run select queries, and there are even additional functions you can add to your select queries as well, where if instead of just selecting the values of columns, I want to compute the average duration of a particular category of flights, or I want to count.


[User] Please transcribe this text

[Assistant] How many flights are coming out of New York or I want to find the longest flight that goes to London or the shortest flight that goes to London or I want to add up all of the durations for a whole bunch of flights. Maybe they're flights that are connected to each other and I want to add up the total travel time that might take.


[User] Please transcribe this text

[Assistant] SQL has a number of built-in functions that allow us to perform these sorts of calculations.


[User] Please transcribe this text

[Assistant] So a couple of different SQL commands we've now taken a look at. We've taken a look at create table that allows us to create a new table, insert that lets us add data to a table, and then select which lets us take data inside of the table and retrieve it.


[User] Please transcribe this text

[Assistant] But of course, often when we're dealing with databases, the data doesn't just get added, the data changes in some way. So we also need some way of being able to update data after it's already inside of our database. And to do that, there's another query for that, which is an update command that we can execute on our database.


[User] Please transcribe this text

[Assistant] And that command looks something like this. Again displayed on multiple lines, but you could put this entirely just on one line. SQL doesn't really care if you add line breaks, it just knows that when it sees a semicolon at the end of the command, that is the end of this particular command.


[User] Please transcribe this text

[Assistant] But here what I've said is use the update keyword to say I would like to update a table. What table would I like to update? I'd like to update the flights table.


[User] Please transcribe this text

[Assistant] And then what would I like to do? Well, I'd like to set the duration equal to 430.


[User] Please transcribe this text

[Assistant] So whatever the value of duration happens to be right now, change it to 430.


[User] Please transcribe this text

[Assistant] Just as in a select clause, I could say where something equals something or where and then some other clause to specify where I want the rows to be selected from. Likewise, to an update, I can say set duration equal to 430.


[User] Please transcribe this text

[Assistant] Where a particular condition is true. So here, I'm going to look through the flights table, find myself all of the flights where the origin is New York and the destination is London. And for those rows, I'm going to update the value of the duration column, setting the duration column equal to 430.


[User] Please transcribe this text

[Assistant] So using that syntax, I can take data and update it, changing one value to another value by pinpointing which row or rows I would like to change. If I only want to change one row, I might do like update flights,


[User] Please transcribe this text

[Assistant] And in addition to inserting data, selecting data, and updating data, the last main command we'll concern ourselves with is the ability to delete data. The ability to take a row and say I'd like to get rid of it, or take multiple rows and get rid of them. And so a command like delete from flights where destination equals Tokyo,


[User] Please transcribe this text

[Assistant] As you might imagine, deletes from the flights table, all of the rows satisfy this condition, where the destination is equal.


[User] Please transcribe this text

[Assistant] And there are a couple other clauses that can be used to add the SQL queries as well, just to add additional functionality. If I don't want all of the rows to come back from a particular SQL query, I can limit the results that come back.


[User] Please transcribe this text

[Assistant] So normally select star from flights would get me all of the flights inside of the table. But I could say select star from flights limit five to just say, you know what, I only want five results to come back from this table.


[User] Please transcribe this text

[Assistant] Order by allows me to decide how the results are ordered inside the results that come back. So I could say select star from flights, order by destination or order by duration to get all of the flights in order by how long they are.


[User] Please transcribe this text

[Assistant] Group by allows me to group a whole bunch of rows together. So if I wanted to group all of the flights by their origin, so I can get all of the flights leaving New York and all the flights leaving London and so forth, I could do something like select star from flights group by origin to group flights by their origin as well.


[User] Please transcribe this text

[Assistant] And having is a constraint I can place on group by to say that I would like to select all of the flights from the grouping them by their origin, but they need to have a count of at least three, meaning there needs to be at least three flights that are leaving from that particular city.


[User] Please transcribe this text

[Assistant] For all of these particular clauses, these are helpful to know if you're going to be directly writing SQL. We won't worry about them too much here, in particular because fairly shortly we're not going to be writing SQL ourselves.


[User] Please transcribe this text

[Assistant] We're going to just be writing Python code and Django is going to under the hood be manipulating the database and creating the SQL commands that it is going to run on the underlying database. And so we will see how we don't actually need to worry about writing the specific syntax, but Django is going to handle much of that for us.


[User] Please transcribe this text

[Assistant] And so here now, we have a flights table. A table that keeps track of all the flights that we have, organizing them by their ID and their origin and their destination and their duration.


[User] Please transcribe this text

[Assistant] But oftentimes when we're dealing with data, especially in a larger database, we don't just have one table of data. We have multiple tables of data. And those multiple tables might relate to each other in some way. And let's take a look at an example of how that might come about. We're going to introduce a concept that we'll call foreign keys. And we'll see what that means in just a moment.


[User] Please transcribe this text

[Assistant] So here again is our flights table. The flights table has four columns, an id, origin, destination, and duration.


[User] Please transcribe this text

[Assistant] But of course, in New York, there are multiple airports in New York, for instance. And so it might not make sense for me to just label each origin or each destination just by the name of the city. Maybe I also want to give the three-letter airport code that corresponds to the airport to which I'm referring in this case.


[User] Please transcribe this text

[Assistant] And so how would I encode into this table not only the origin, but also that city's airport code. And not only for the destination, the name of the city, but also the airport code for that airport as well. Well, I could just add more columns. I could say something like, all right, now we have this table that has an ID.


[User] Please transcribe this text

[Assistant] But here now, the table is starting to get fairly wide. There are a lot of columns here. And in particular, there's some duplicate data that I've repeated. My mention of Paris is associated with this particular three-letter code. And the same thing for New York and other airports as well. There is some messiness in the structure of this data.


[User] Please transcribe this text

[Assistant] And so often what we'll want to do is we begin to deal with data in larger and larger sets with more and more columns, is we'll want to normalize this data, separating things out into multiple different tables that just reference one another in some way.


[User] Please transcribe this text

[Assistant] And so instead of just having a single flights table, what we might consider doing is saying that flights are one type of object.


[User] Please transcribe this text

[Assistant] But another type of object that I care about is like an airport. And so I might just have a separate table just for airports, where this table has three columns.


[User] Please transcribe this text

[Assistant] A column for the ID of the airport, just some unique number that can identify a particular airport. One column for the three letter code for that airport. And one letter for the city, or one column for the city where that airport is in. And now this is a much more straightforward, simpler representation of all of the airports.


[User] Please transcribe this text

[Assistant] And the question becomes, what happens to my flights table? That my flights table that here had an ID, origin, destination, and duration?


[User] Please transcribe this text

[Assistant] Where the type of origin and destination were in this case just text. Text based data representing the name of the city from which the flight is departing or to which the flight is arriving.


[User] Please transcribe this text

[Assistant] Well now that I have this separate airports table, where every row in the airports table has its own unique ID, then what I can do in this case is instead of storing an origin and a destination as text,


[User] Please transcribe this text

[Assistant] I can store what we'll call a foreign key, a reference to a key in another table and rename these columns to origin ID and destination ID that instead of storing text are going to store a number.


[User] Please transcribe this text

[Assistant] Whatever airport number one happens to be. And I could go to the airport stable,


[User] Please transcribe this text

[Assistant] Look up which airport has an ID of 1, and that would tell me the origin of this flight. And if I went to the airport's table and looked up which airport had an ID of 4, that would tell me the destination of this flight as well. So by combining now two different tables,


[User] Please transcribe this text

[Assistant] One table for representing airports and one table for representing flights, I'm able to connect these two different tables together by way of a foreign key. Some columns inside of my flights table, namely the origin ID column and the destination ID column, that together allow me to reference information stored inside of another table as well.


[User] Please transcribe this text

[Assistant] And as you imagine this sort of airline's database growing and storing more different kinds of data, the ability to relate tables to each other is going to become incredibly powerful. So one thing you might imagine is that in addition to storing airports and storing flights, an airline probably also needs to store information about its passengers, like who is on which flight.


[User] Please transcribe this text

[Assistant] And so you could imagine constructing a passengers table that has an ID column to uniquely identify every passenger, a first name column that stores every passengers first name, a last name column for storing their last name, and a flight ID column for storing what flight that passenger happens to be on.


[User] Please transcribe this text

[Assistant] Now as we begin to design these tables, we have to think about what the implications of that design happen to be. And in the case of this passengers table, it does seem that there is a limitation on the table design that I have created. And namely, if you think about it, you'll see the limitation of this table design is that any particular row


[User] Please transcribe this text

[Assistant] And so this starts to get at the idea of different types of relationships that rows and a table can have to one another.


[User] Please transcribe this text

[Assistant] One type of relationship is a many to one relationship or a one to many relationship where I can express the idea that one flight can be associated with many different passengers.


[User] Please transcribe this text

[Assistant] And one way we can approach it is by creating a separate table for storing people.


[User] Please transcribe this text

[Assistant] But I can have a people table where every person has an ID, has a first name, and has a last name, same as before, but I'm no longer storing flight information inside of the table. I've cleaned my setup up, I'm only storing people in this table, and nothing about their flight information.


[User] Please transcribe this text

[Assistant] And then I'll have a separate table for dealing with passengers on the flight and mapping people to their flights.


[User] Please transcribe this text

[Assistant] And we can think about what does that table need to look like? Well, I need some sort of table that is going to relate people to what flights they happen to be on. So odds are we're going to need one column that is a foreign key that references this people table. And we'll need another column that is a foreign key that references the flights table such that I can relate those two tables together. And so that table could look like this.


[User] Please transcribe this text

[Assistant] This now is a simplified passengers table that only has two columns. It has a person ID column and a flight ID column.


[User] Please transcribe this text

[Assistant] And the idea of this table now is it's known as an association table or a join table that just associates one value from one table with another value from another table.


[User] Please transcribe this text

[Assistant] That this row here, 1 and 1, means the person with an ID of 1.


[User] Please transcribe this text

[Assistant] Is on flight number one. And I could look up that person inside of the per people table, look up that flight inside of the flights table, and figure out who the person is and what flight they're on. And down here, two and four means whoever the person with an ID of two is, is on whichever flight happens to have an ID.


[User] Please transcribe this text

[Assistant] And so this now has allowed us to be able to represent the types of relationships we want. We have a table for airports and a table for flights. And any flight is going to map to two different airports, one destination, one origin. And any airport might appear on multiple different flights. It's sort of a one to many relationship.


[User] Please transcribe this text

[Assistant] And then over here, when it comes to passengers, we've stored people inside of a separate table.


[User] Please transcribe this text

[Assistant] And then had a many-to-many mapping between people and flights. So that any person could be on multiple different flights. Like here, for example, person number two is on both flights one and four. And likewise, a flight could have multiple people. So in this case, flight number six has passengers five and six that are on that flight as well. We've been able to represent those relationships.


[User] Please transcribe this text

[Assistant] Of course a byproduct of doing this is that now our table is a-


[User] Please transcribe this text

[Assistant] And now it's a little harder for me to figure out who's on which flight. I have to look at this data, look up people in the people table, look up flights in the flights table, and somehow associate all of that information back together in order to draw any sort of conclusion.


[User] Please transcribe this text

[Assistant] So the syntax for a join query might look something like this. And here we'll go back to just a two table setup where I have flights and passengers where every passenger is associated with one flight. You could extend this and join multiple tables to deal with our more complex example as well.


[User] Please transcribe this text

[Assistant] But here, I'd like to select every person's first name and their origin and their destination.


[User] Please transcribe this text

[Assistant] And I'm gonna select that from the flights table, but I need to join it with the passengers table.


[User] Please transcribe this text

[Assistant] And then I say on to indicate how it is these two tables are related to one another.


[User] Please transcribe this text

[Assistant] And in this case I'm saying the way these two tables are related to one another is that the flight ID column of the passengers table


[User] Please transcribe this text

[Assistant] Is associated with the ID column of the flights table. The flights table has an ID that uniquely identifies every flight. And the passengers table has a flight ID column that uniquely identifies the flight that we're referring to for this particular passenger.


[User] Please transcribe this text

[Assistant] Are going to be drawn from that table of flights and the first name is going to be drawn from the table of passengers. But by using a join query, I've been able to take data from two separate tables and join them both.


[User] Please transcribe this text

[Assistant] And there are a number of different types of join queries that I can run. What we saw here was just the default join, which is otherwise known as an inner join, where effectively an inner join will take the two tables, it will cross compare them based on the condition that I specified.


[User] Please transcribe this text

[Assistant] And only return back to me the results where there's a match on both sides, where we match a passenger's flight ID with an ID in the flights table.


[User] Please transcribe this text

[Assistant] And there are various different kinds of outer joins if I want to be okay with the idea that maybe something on the left table that I'm joining doesn't match with anything on the right, or that maybe something on the right table doesn't match with something on the left, but just know there are other types of join queries that I can run.


[User] Please transcribe this text

[Assistant] Other strategies that can be helpful when dealing with SQL tableism are optimizations we can make to make queries more efficient. And so one thing we can do with our tableism is to create an index on a particular table.


[User] Please transcribe this text

[Assistant] And you can think of an index as kind of like the index in the back of a book, for example, where if you wanted to be able to search for a topic in a textbook, you could open the textbook and just page by page, look for every topic and just try and find the topic you're looking for. But often what you'll be able to do if the table has an index is go to the index of the book,


[User] Please transcribe this text

[Assistant] Find the topic you're looking for and that will quickly give you a reference for how to get to the right page in question. And an index on a table operates in much the same way. It is an additional data structure that can be constructed and it does take time and memory to be able to construct this data structure and to maintain it anytime you update the data inside the table.


[User] Please transcribe this text

[Assistant] But once it exists, it makes querying on a particular column much more efficient. That you can very quickly look something up in the index and find the corresponding rows that go along with it. And so here we can have a command like create an index that we're going to call name index.


[User] Please transcribe this text

[Assistant] On the passengers table, and in particular on the last name column.


[User] Please transcribe this text

[Assistant] I'm going to say something like, I expect that as I query this table, I'm pretty frequently going to be looking up passengers by their last name. So I would like to create an index on that table to be able to more efficiently search for a passenger based on their last name as well.


[User] Please transcribe this text

[Assistant] And so that's just a general overview of what SQL syntax is all about. A syntax that we can use to be able to create data tables inside of which are storing rows of data where every row consists of some number of columns and every column has a type. You have the ability to create tables, add data to them, update, delete, and get data out of those tables as well.


[User] Please transcribe this text

[Assistant] But as we begin to introduce these new technologies, there are always risks and potential threats that are associated with those technologies as well. And in SQL, the key one to be aware of is what's known as a SQL injection attack, a security vulnerability that can happen if you're not careful about how it is you actually execute your SQL commands.


[User] Please transcribe this text

[Assistant] And so where might this come about? You might imagine, for instance, that if a database has some number of users, you might be storing those users inside of a database.


[User] Please transcribe this text

[Assistant] For instance, in a user's table where there's a username column and a password column. Though in practice you probably wouldn't want to store passwords in cleartext. Let's imagine here, for example, that you are storing usernames and passwords inside of a table.


[User] Please transcribe this text

[Assistant] And we have a login form for a website that looks like this, where you get to type in your username and your password, and so if someone types in their username and password, what might happen is that the web application might look, select star from users,


[User] Please transcribe this text

[Assistant] Where username equals this particular username, highlighted here. We're just going to substitute the username right there. And password equals, and we'll substitute the password over there.


[User] Please transcribe this text

[Assistant] So if someone tries to log into our site, like Harry logs in with a password of 12345, what we might do is run the select query and say select star from users where username is Harry.


[User] Please transcribe this text

[Assistant] Seems like a bit of a strange username to type in. And it doesn't matter what they put in their password here now. The result might be...


[User] Please transcribe this text

[Assistant] So here, the vulnerability within the SQL syntax, if we're not careful about when we're running SQL syntax, we could be running untrusted SQL commands that some hacker or some adversary has been able to plug in to our program.


[User] Please transcribe this text

[Assistant] So how do we solve this sort of problem? Uh, one strategy is to escape these characters. Escaping just meaning add some backslashes that just makes sure that SQL knows to treat these as a literal quotation mark and a literal dash and not as like special SQL syntax of any sort.


[User] Please transcribe this text

[Assistant] Another strategy is to use an abstraction layer on top of SQL so that we don't have to write the SQL queries at all. And that's in fact what we're about to do as we transition to the world of Django to take a look at how when we begin to use a web framework like Django, we now have the ability to not worry about the nuances of the syntax of SQL


[User] Please transcribe this text

[Assistant] And just deal a little more high level with what our models are. What are the types of objects that we're dealing with and interacting with inside of this application.


[User] Please transcribe this text

[Assistant] One other concern worth noting about with regards to SQL is the possibility of race conditions.


[User] Please transcribe this text

[Assistant] And a race condition is something that might happen anytime you have multiple events that are happening in parallel threads, so to speak. That you have one thing happening and another thing happening simultaneously. You might imagine that in the case of social media sites where you can like a post, like an image on Instagram or a tweet on Twitter, for example.


[User] Please transcribe this text

[Assistant] What would happen if two people tried to like the same post at the same time?


[User] Please transcribe this text

[Assistant] If we're not careful about how we run those particular SQL queries, there's a potential for us to be able to get, uh, race condition problems.


[User] Please transcribe this text

[Assistant] Where we end up like trying to query for the number of likes that a post has and then another person tries to do the same thing and there are conflicts when we try and update it where the result might not be what we would expect it to be. And there are a number of unexpected results that can happen when we deal with problems related to race conditions where multiple things are happening simultaneously. How do we solve those problems?


[User] Please transcribe this text

[Assistant] Well, one strategy is to sort of place a lock on the database to say, all right, while I'm working on this database, nobody else can touch this data. Let me finish this transaction, so to speak, finish working on this particular transaction.


[User] Please transcribe this text

[Assistant] And making all the changes I need to make to the database and only after I'm done, I can sort of release the lock, let someone else go ahead and modify the database as well.


[User] Please transcribe this text

[Assistant] So a number of concerns to be aware of as we begin dealing in this world of SQL and trying to work with databases.


[User] Please transcribe this text

[Assistant] So now that we've taken a look at the syntax of SQL, understanding how these tables work, how they're structured, and what it is that we can add to those tables,


[User] Please transcribe this text

[Assistant] Let's go ahead and turn our attention, in particular, to Django models, which are a way of representing data inside of a Django application, because where Django is really going to get powerful in designing our web applications is the ability to represent data in terms of these models.


[User] Please transcribe this text

[Assistant] And so we're gonna go ahead and try and create a web application that is going to represent like what an airline might want to store inside of its own web application as well.


[User] Please transcribe this text

[Assistant] I'll go ahead and go into the airline directory, open that up in my code editor. Before I actually begin editing any code, remember that every Django project needs to have one or more apps within it. So the first app that I'll create for this airline is I'll start an app for keeping track of flights. So keeping track of flight related information.


[User] Please transcribe this text

[Assistant] Like origins and destinations and durations and what passengers are on those sites.


[User] Please transcribe this text

[Assistant] When I create a new app, first thing I'll need to do is go into settings.py inside of airline and go ahead and add this app as an installed app, right? So flights is now an app that I have installed. And then what I'll want to do,


[User] Please transcribe this text

[Assistant] Which is again that table of contents for all the URLs I can get to for this particular web application. I'll import include because I want to do is when someone visits the path of flights slash something, I want to take them to flights.urls, mapping them to the urls.py file that will be inside of my flights application.


[User] Please transcribe this text

[Assistant] Of course, now I need a urls.py file inside of my flights application. So I go into flights and create a new file that I'll call urls.py.


[User] Please transcribe this text

[Assistant] But before I begin dealing with actual URLs, the first thing I'm going to want to do is create some models. Models are going to be a way of creating a Python class


[User] Please transcribe this text

[Assistant] Is inside of every app that gets created, in this case called Flights, there's a models.py file. One that we haven't looked at before, but this is going to be the place where we get to define what models are going to exist for our application.


[User] Please transcribe this text

[Assistant] Every model is going to be a Python class, and you can think of this as having one model for each of the main tables we care about storing information about. So let me define a new class called Flight that is going to inherit from models.model. So I'm creating a new class called Flight that is going to be a model.


[User] Please transcribe this text

[Assistant] And then I need to provide inside of this class all of the parameters that a flight have. What properties does a flight have that I might want to keep track of? Well, a flight has an origin.


[User] Please transcribe this text

[Assistant] And the origin is going to be a models.char field. And this is all documented on Django's website in terms of the various different types of fields that exist that I can include inside of a Django model. Where here I'm saying, all right, here is a character field.


[User] Please transcribe this text

[Assistant] Whose max length is going to be, let's say, 64. I'll assume that most city names are not going to go longer than 64 characters. That seems like a reasonable maximum length for the origin of the flight, for example.


[User] Please transcribe this text

[Assistant] Every flight will also have a destination, which will be a character field whose max length is also 64. And every flight will have a duration, which will just be an integer field.


[User] Please transcribe this text

[Assistant] So now, this is my very first Django model. It is a class called Flight, where I've defined all of the properties that a flight has, and then using Django syntax to find what type they should have as well. Every flight has an origin, has a destination, and has a duration.


[User] Please transcribe this text

[Assistant] But of course nothing here has actually modified the database that Django is using in order to store information about my web application. And we can see if we in fact go back to airline and I type ls, what you see here is that there isn't yet a database that exists. I just have an airline directory, a flights directory, and a manage.py file.


[User] Please transcribe this text

[Assistant] So what I'd like to do is somehow tell Django that you should update the database to include information about the models that I have just created.


[User] Please transcribe this text

[Assistant] And this is a process that we refer to in Django and more generally as migrations. I create a migration to say here are some changes that I would like to apply to the database.


[User] Please transcribe this text

[Assistant] And then I migrate them to tell Django, all right, take those changes and actually apply them to the database. So it's a two step process.


[User] Please transcribe this text

[Assistant] One is creating the migration, the instructions for how to actually go about manipulating the database, and then one to take that migration step of saying now take those instructions and actually apply them to the underlying database.


[User] Please transcribe this text

[Assistant] We can make the migrations via a command. Again, we'll use the manage.py script that has a number of different commands that allow us to control various parts of the application. I'll use python manage.py and then make migrations.


[User] Please transcribe this text

[Assistant] And now what we see is we've created a migration inside of 0001 underscore initial dot pi, where in this migration it's created a model called flight.


[User] Please transcribe this text

[Assistant] And so if I go ahead and look at the migrations directory, I see this file has been created for me. I didn't have to create it myself.


[User] Please transcribe this text

[Assistant] And what this file is, is it is instructions to Django.


[User] Please transcribe this text

[Assistant] For how to manipulate the database to reflect the changes I have made to the model. That here is an instruction to Django to create a new model called flight that has these particular fields inside of it. And it's basing this off of the changes that I made to models.py. The model that I added is now reflected in this migration.


[User] Please transcribe this text

[Assistant] And now if I want to apply the migration, actually apply it to Django's database, I can run python manage.py migrate.


[User] Please transcribe this text

[Assistant] To go ahead and apply these migrations. There are a bunch of default migrations that get applied as well, but notice that one of the migrations that gets applied is this one here, applying flights dot zero zero zero one underscore initial to say let's go ahead and apply that migration, create that table that is going to represent flights.


[User] Please transcribe this text

[Assistant] And if I type ls now, you'll see that now I have a db.sqlite3 file, a SQLite database that is going to contain a table that is going to store all of my flights.


[User] Please transcribe this text

[Assistant] And so how can I actually begin to manipulate this data? How can I interact with these?


[User] Please transcribe this text

[Assistant] With these sorts of models, I could use direct SQL syntax by opening up this database file and running commands, but Django provides some nice abstraction layers on top of it so that I don't actually need to execute those commands myself. I can begin to work more generally with Python classes and variables and things that I'm used to inside the Python language.


[User] Please transcribe this text

[Assistant] So I can enter Django's shell, or I can just run python commands, by running python manage.py shell.


[User] Please transcribe this text

[Assistant] And what this does is open up a shell or a console where I can begin to write Python commands that get executed on this web application. And the first thing I'd like to do is from flights.models, let me just import flight.


[User] Please transcribe this text

[Assistant] So flights is the name of my app, models is the name of that file. I'm importing the flight class from that models file that I've just created. And now what I can do is I can create a new flight. I can say something like F equals a flight whose origin is New York and whose destination is London.


[User] Please transcribe this text

[Assistant] And his duration equals 415 minutes. And then I can say f.save to save that new flight that I have created. And this syntax now, and I'll go ahead and make it a little bit bigger so you can see it a little easier, is my way


[User] Please transcribe this text

[Assistant] Of inserting data into this table. I don't need to use an insert query in SQL.


[User] Please transcribe this text

[Assistant] I just have to write a Python command, and Django knows that when I create a new flight and save it, that it should run an insert command on the underlying SQL table. Where here, I've created a new flight with this particular origin and destination and duration, and I've gone ahead and saved that flight as well.


[User] Please transcribe this text

[Assistant] And if I want to query that flight, get information about that flight, I can say something like, flight.objects.all is the equivalent of like a select all. Get me all of the flights that exist inside of my database.


[User] Please transcribe this text

[Assistant] And here, I see I get back a query set, which is just a set of results.


[User] Please transcribe this text

[Assistant] And here I have one flight that came back, flight object one. So a flight has been created for me with id one. Now flight object one, probably not all that helpful of a name. It'd be nicer if this model had a cleaner way of seeing the name of a particular, uh, of a particular flight, for example. And it turns out we can do that. That any model, I'll go back to the code inside of models.py,


[User] Please transcribe this text

[Assistant] Any model can implement, uh, double underscore stir function.


[User] Please transcribe this text

[Assistant] Which returns a string representation of that particular object. And this applies not just to jingle models, but to Python classes more generally. That if this function returns a string representation of the object, let's go ahead and return a formatted string that is self.id, I'll say self.origin to self.destination.


[User] Please transcribe this text

[Assistant] So here what I said is that the string representation of any flight is going to be a string that gives its ID and then says, all right, origin to destination. Just a nice clean name that is going to represent this particular flight. So now, if I go back.


[User] Please transcribe this text

[Assistant] To the shell, by running python manage.py shell.


[User] Please transcribe this text

[Assistant] I can say, alright, let's let a variable called flights be equal to flight.objects.all.


[User] Please transcribe this text

[Assistant] And now flights is going to be this flight. Flight one, New York to London. It now has a much nicer string representation of the name, which just makes it a little bit easier to interact with. Uhm, if I wanted to get just that one flight, I can say flight equals flights.first. Flights is a query set. First gets me that first flight.


[User] Please transcribe this text

[Assistant] And so now I have this flight from New York to London.


[User] Please transcribe this text

[Assistant] And just as in any Python object, I can begin to access properties of that object. I can say, alright, flight, what is your ID? Flight, what is your origin?


[User] Please transcribe this text

[Assistant] Flight, what is your destination? Flight, what is your duration? And I can access as values all of the properties of this flight that I ultimately care about. And if I want to delete the flight, I can say something like flight.delete.


[User] Please transcribe this text

[Assistant] Now ultimately though, this is not the model that I actually want to represent my flight. Because here again, I'm using a character field, a char field, for things like origin and destination, when in reality I'd probably like to use something like another table for representing airports, and then some relationship between every flight and an airport.


[User] Please transcribe this text

[Assistant] So let's go ahead and try and implement that idea now that I can go back into models.py and create a new class. I'll create a class called Airport.


[User] Please transcribe this text

[Assistant] That is also a model. And I'd like for this airport class to have a code.


[User] Please transcribe this text

[Assistant] Which is a character field with a max length of 3 for the airport's code, as well as a city, which would be a character field with a max length of 64.


[User] Please transcribe this text

[Assistant] And let's also give this airport a string representation. We'll say that the string representation of an airport will just be the city of the airport and then in parentheses the code of the airport. So it'll be something like New York and then in parentheses JFK to represent a particular airport. And now our flight model needs to change a little bit.


[User] Please transcribe this text

[Assistant] No longer will origin and destination be character fields that are just storing text, but instead, origin is going to be a foreign key.


[User] Please transcribe this text

[Assistant] A foreign key that references another table, like the airport table.


[User] Please transcribe this text

[Assistant] And then I can provide some additional arguments. So this alone would be enough, but I can add some additional arguments like onDelete equals models.cascade. So what does this mean? Well, when I have tables that are related to each other,


[User] Please transcribe this text

[Assistant] SQL needs some way of knowing what should happen if you ever delete something. If I have a flight from JFK to London and I later in the, later in time decide to delete JFK airport from my database, what should happen to that flight? Like what happens to flights when the thing that it is referencing gets deleted?


[User] Please transcribe this text

[Assistant] And the other argument that I'm going to provide is what's called a related name. And a related name, as we'll see in just a moment, is going to be a way of me accessing a relationship in reverse order. That from a flight, I can take a flight and say .origin to get the flight's origin in airport.


[User] Please transcribe this text

[Assistant] But the other question I want to ask is in the reverse order. If I have an airport, how do I get all of the flights that have that airport as an origin?


[User] Please transcribe this text

[Assistant] And so here if I give a related name to this foreign key, Django will automatically set up the relationship going in that opposite direction. And so here, well if we have an airport and I want to know all of the flights that have that airport as their origin, the reasonable name for a related name here is something like


[User] Please transcribe this text

[Assistant] So if I have an airport, I can access all of the departures, which gets me all of the flights that are leaving from that airport.


[User] Please transcribe this text

[Assistant] And I'll likewise do the same thing here for destination. Instead of a character field, it's gonna be a foreign key. Uh, it's going to reference airport.


[User] Please transcribe this text

[Assistant] When we delete it, we'll go ahead and cascade, and the related name will be arrivals. Because if I have an airport, I might want to access all of the arrivals, all of the flights that correspond to flights that are arriving at that particular destination.


[User] Please transcribe this text

[Assistant] And so now I've done two things. I've added a new class called Airport, and I've modified my existing flight model.


[User] Please transcribe this text

[Assistant] So this is changed in my Python code, but it hasn't yet changed in my database. So in order to make the change in the database, again, it's a two-step process. Step one, python manage.py make migrations to say look for any new changes that have been made to models.py.


[User] Please transcribe this text

[Assistant] And go ahead and create a migration instruction for how to make those changes to the database. And here we see that we've created a new migration file.


[User] Please transcribe this text

[Assistant] And this migration is going to create a model called airport, and it's also going to alter the destination field and alter the origin field on my flight model.


[User] Please transcribe this text

[Assistant] Because as we know, we've changed destination and origin to no longer be character fields, but to instead be references to a particular airport. So that's something that's going to need to change in the database. And to make that change, I can run something like


[User] Please transcribe this text

[Assistant] Python manage.py migrate to go ahead and apply those changes. We've now applied this migration that we just created and our database is now up to date.


[User] Please transcribe this text

[Assistant] So what can we do? Well now I can go ahead and go back into the shell.


[User] Please transcribe this text

[Assistant] And I'll just go ahead and import from flights.models import star, import everything.


[User] Please transcribe this text

[Assistant] And I can now create an airport. I can say something like JFK equals an airport whose code is JFK and whose city is New York, for example. And then save that. I can create a London one, so LHR is an airport whose code is LHR and whose city is London.


[User] Please transcribe this text

[Assistant] And I can save that. Uh, you know, you could create more. I could say CDG equals an airport whose code is CDG and city is Paris. And maybe we'll do one more. We'll say NRT is the airport whose code is NRT and whose city is Tokyo, for example.


[User] Please transcribe this text

[Assistant] So I've now created four airports. I've created a flight and saved it. If I type F just for my flight, I see that, all right, this is a flight from New York to London. But I can also say, what is F dot origin?


[User] Please transcribe this text

[Assistant] And to write f.origin, that is now an airport object.


[User] Please transcribe this text

[Assistant] It's JFK in particular, and I can do f.origin.city to get the city of the origin, which is New York, f.origin.code to get the code of that airport, which is JFK. And if I start with an origin, something like JFK or London Heathrow, I can say lhr.arrivals.


[User] Please transcribe this text

[Assistant] To go ahead and .all to get all of the arrivals, all of the flights arriving in London Heathrow and it looks like there's just one of them which is this flight that I've just created from New York that is going to London as well. And so this now gives us the ability


[User] Please transcribe this text

[Assistant] I can just interact with these classes and these properties on the classes, and Django takes care of the process for me of figuring out what the underlying SQL queries should be, executing those queries, and just giving those results.


[User] Please transcribe this text

[Assistant] And we can begin now to design a web application around this idea.


[User] Please transcribe this text

[Assistant] But I can go into urls.py and let's add a URL pattern that says, you know, the default route. We'll go ahead and load the index view. Give it a name of index. Same as similar things we've seen from last time. And now what should we do in the index view?


[User] Please transcribe this text

[Assistant] Well the index view, let's go ahead and say, what I would like to do is just display a list of all the flights. So I might, from dot models, import flight and airport. Or maybe I just need flight, I just want a list of all the flights. So I'm going to import flight from all of my models.


[User] Please transcribe this text

[Assistant] And now what I'd like to do is return, let's go ahead and render a template called flight slash index dot html.


[User] Please transcribe this text

[Assistant] And give index.html access to a variable called flights. And what is that variable going to be equal to? It's going to be equal to flight.objects.all to get me like all of the flights that I would like to put right here.


[User] Please transcribe this text

[Assistant] Alright, so what can I do from now? Now what I need to do is actually create those individual templates. So inside of flights, I'll create a new folder called templates.


[User] Please transcribe this text

[Assistant] Inside of which I'll create a new folder called Flights. Inside of which I'll go ahead and create a layout.html, much as we've done before, where that layout is going to contain the basic structure of our HTML page. So a head section whose title is Flights.


[User] Please transcribe this text

[Assistant] Much as before, this is the default layout for this particular page.


[User] Please transcribe this text

[Assistant] I'm going to display an h1 that just says flights. And let's now create an unordered list where I can now loop over for flight in flights.


[User] Please transcribe this text

[Assistant] End four to end the loop. But inside the loop, let me create a list item where I just print out, like, uh, flight. Maybe I'll print out the flight and then flight.id to print out, like, flight one, flight two, flight three. And then I'll print flight.origin to flight.destination. So what I've done here is create a template.


[User] Please transcribe this text

[Assistant] That I'm going to give access to a variable called flights, where flights is going to be a variable that represents all of the flights that I query. By running flight.objects.all, that is my way using Django's API, using the functions that it has given me access to, to say take the flight and get all of the flights that are stored inside of Django's database.


[User] Please transcribe this text

[Assistant] Where I can access properties of that flight. Say flight this ID from origin to a particular destination.


[User] Please transcribe this text

[Assistant] I'll go ahead and go into my terminal, run python, manage.py, run server, which again is how we run a Django web application.


[User] Please transcribe this text

[Assistant] And now if I go to that URL, slash flights this time, because that's the URL, what I see is exactly what I would expect to see. An unordered list that just so happens to have flight one, New York to London displayed there. It is taking data from my database and now displaying it inside of this template.


[User] Please transcribe this text

[Assistant] And if I were to add new flights, it would also update on this page as well. So if I go ahead and go back, go into the shell, python manage.py shell, I'll go from flights.models import star. Let's go ahead and


[User] Please transcribe this text

[Assistant] Well, alright, let's add a flight from Shanghai to Paris, for example. Well, how do I get the airports for Shanghai and Paris? Well, it turns out that if I want to get like Shanghai, I can say like Shanghai equals airport.objects. and then I can say, if I do airport.objects.all,


[User] Please transcribe this text

[Assistant] That gets me all of the airports, for example. Oh, and it seems I don't actually have a Shanghai one. But I can add one if I wanted to. But if I do airport.objects.all, that again gives me all of them. But if I want to filter my airports list, not get all of the airports but just get some of them, I can say airport.objects.filter.


[User] Please transcribe this text

[Assistant] And I can say like, get me all the airports where, uhm, the city is New York, for example.


[User] Please transcribe this text

[Assistant] So again, airport.objects.filter lets me constrain the results that come back. Not get me all of the airports, but only get me airports whose city is New York, for example. And it's only giving back one, so I could say, .filter city equals New York.


[User] Please transcribe this text

[Assistant] .first to say take that query set and just get me the first and only thing in that query set and that gives me airport New York.


[User] Please transcribe this text

[Assistant] A simplified way of doing the same thing, if you know you're only going to get one result back, if I can say something like airport.objects.get, which will only get one result if it knows that there's only going to be one airport with the city of New York, that too will return to me New York JFK Airport.


[User] Please transcribe this text

[Assistant] But it will throw an error if ever there's more than one, or if there's none, for example.


[User] Please transcribe this text

[Assistant] So we'll go ahead and save that inside of JFK, and we'll go ahead and create a flight that is going, uh, from New York to Paris, for example. If I can do cdg, equals airport.objects.get, city equals Paris.


[User] Please transcribe this text

[Assistant] And now I have this variable CDG, which represents the airport Paris. And if I want to create a new flight that goes from New York to Paris,


[User] Please transcribe this text

[Assistant] I now see that I have two flights. One flight that's going from New York to London, one flight that's going from New York to Paris.


[User] Please transcribe this text

[Assistant] What I'd really like to be able to do is just very simply to add it via a web interface, via the web, be able to say, alright, let me add a new flight that goes from location one to location two.


[User] Please transcribe this text

[Assistant] And it's possible using the information we know now to build a webpage that does just this.


[User] Please transcribe this text

[Assistant] But Django is built on this idea that it doesn't want you the programmer to have to repeat work that other people have already done. And this process of trying to define models and very quickly be able to create and edit and manipulate models is so common that Django has already built for us an entire app


[User] Please transcribe this text

[Assistant] And this is an app that we've seen traces of already, that if we remember that urls.py file,


[User] Please transcribe this text

[Assistant] From inside of our application, we saw that we added a path for our own app, but there was already a path given to us by default slash admin that takes us to the admin app as well.


[User] Please transcribe this text

[Assistant] And so in order to use the admin app, we need to create an administrative account inside of our Django web application. And the way to do that is via the command line. I can run python manage.py create super user. It's going to ask me for my name. I'll go ahead and type in my username.


[User] Please transcribe this text

[Assistant] My email address, and it's also gonna ask for a password. I can just make up a password that I would like to use.


[User] Please transcribe this text

[Assistant] Retype it in just to confirm it. And now Django has created a super user account for me in this web application so that I, using these credentials, have the ability to visit the web interface for the admin app and actually manipulate some of these underlying models.


[User] Please transcribe this text

[Assistant] So in order to do this, the first thing I need to do is take my models and add those models to the admin app. So inside of models.py, I have a class called Airport and a class called Flight.


[User] Please transcribe this text

[Assistant] And if we look at the files I have, there's another file we haven't really looked at yet called admin.py inside of my app.


[User] Please transcribe this text

[Assistant] And inside of admin.py, I'll first from my models import flight and airport.


[User] Please transcribe this text

[Assistant] And what this is going to do is it is going to tell Django's admin app that I would like to use the admin app to be able to manipulate airports and to be able to manipulate flights as well.


[User] Please transcribe this text

[Assistant] And so let's take a look at this admin app and see how it actually works. I can run python manage.py run server.


[User] Please transcribe this text

[Assistant] That will start up the web server. I'll now visit this URL. Instead of going to slash flights, I'll go to slash admin. And this opens up.


[User] Please transcribe this text

[Assistant] This Django administration app. It's not written by me, Django has written this, and it's asking me to log in.


[User] Please transcribe this text

[Assistant] I'll go ahead and log in using those credentials I used a moment ago, typing in my username and password, and what I get here


[User] Please transcribe this text

[Assistant] But importantly, if we notice down here, I now have the ability to add and manipulate airports and flights via this web interface, this Django administrative interface. So now using this interface, I have the ability to manipulate the underlying database to manipulate my models to add and modify data that already exists. So if I click on airports, for example,


[User] Please transcribe this text

[Assistant] I see here, here are all of the airports that I've already added to my database. Tokyo, Paris, London, and New York.


[User] Please transcribe this text

[Assistant] And I can add a new one. I can say let's go ahead and add PVG, which is Shanghai.


[User] Please transcribe this text

[Assistant] And I can either save it, save and continue editing, save and add another. I'm gonna add a couple, so I'll go ahead and save and add another. Let's go ahead and add Istanbul airport as well. Let's add, uh, Moscow as an airport too. And maybe one more, we'll add Lima as well. And I'll just go ahead and click save.


[User] Please transcribe this text

[Assistant] And now I've added a whole bunch of airports all via this web interface. Django was originally created for like news organizations that very quickly wanted to be able to post


[User] Please transcribe this text

[Assistant] I'll click on flights. I see that I already have two flights inside of my database. I have New York to London and New York to Paris.


[User] Please transcribe this text

[Assistant] I'll add a new one. It's letting me choose an origin, destination, and duration. And Django knows that the origin must be an airport. So it's going to give me the opportunity to just choose an airport. Where I can say, okay, Shanghai is the origin, uh, the destination is going to be Paris, and the duration is going to be like 760 minutes, for example.


[User] Please transcribe this text

[Assistant] Not to the admin app, but to my flights app, the app that I wrote myself and go back to slash flights. Now I actually see all of the new flights that I have added to my database via Django's admin interface. I added them to the admin interface and now I see this flight from Shanghai to Paris. I see this flight from Paris to New York as well.


[User] Please transcribe this text

[Assistant] And so now what I might like to do is begin to add some more pages to this web application. Make this web application a little more sophisticated by maybe giving me the ability to like click on a particular flight.


[User] Please transcribe this text

[Assistant] What I'd like is for every flight to have its own page, not just slash flights for all the flights, but slash flight slash one for flight ID one, slash flight slash two for ID two, so on and so forth.


[User] Please transcribe this text

[Assistant] What I can do in order to do that is go back into urls.py


[User] Please transcribe this text

[Assistant] And create a new path. We'll create a path where I'm going to specify a flight ID, which will be an integer. When I do, let's go ahead and load the flight view, whose name will be flight. And now I need to just go to views.py and add a function called flight.


[User] Please transcribe this text

[Assistant] So I'll go back, go into views.py. In addition to an index function, we'll define a flight function that accepts as an argument a flight ID.


[User] Please transcribe this text

[Assistant] So now what is this flight function going to do? Well the first thing I need to do is actually get that flight. I can say flight equals flight dot objects dot get. Get me the flight whose id is equal to flight id, for example.


[User] Please transcribe this text

[Assistant] Or alternatively, Django also lets you say PK instead of ID is a more generic way of referencing the primary key for whatever the primary key happens to be called. The PK in this case is just the ID. But then what I can do is render.


[User] Please transcribe this text

[Assistant] A template like flight slash flight dot html and pass as input to that the flight.


[User] Please transcribe this text

[Assistant] So we're passing it this flight to flight.html. And now I can create a template, create a new file called flight.html, which is going to also extend flight slash layout.html using that same HTML layout and inside the body of the page.


[User] Please transcribe this text

[Assistant] Let's just say something like in big we'll say flight, flight ID and then maybe an unordered list where I can say something like the origin is flight.origin. The destination is flight.destination.


[User] Please transcribe this text

[Assistant] So now I have a page that displays flight information about any particular flight.


[User] Please transcribe this text

[Assistant] And if I go ahead and load not slash flights in my web browser, but slash flight slash one, for example, well now I have information about flight number one, and slash flight slash two gets me information about flight number two. Querying for that particular flight, then printing out its origin, destination, and duration.


[User] Please transcribe this text

[Assistant] Now there's some error checking that we probably should do here. If I try and access a flight that doesn't exist, something like flight 28 for example, I'm gonna get some sort of error that does not exist error, flight matching query does not exist. I might like to control what happens in that situation a little better.


[User] Please transcribe this text

[Assistant] So you might imagine adding some additional error checking to handle those cases as well, but we'll leave it at this just for now.


[User] Please transcribe this text

[Assistant] But now, let's go ahead and add the ability not only to have flights that have airports associated with them, but let's also add passengers to our flights as well to be able to represent passengers that might actually be on these flights too. So I'll go ahead and go back into models.py.


[User] Please transcribe this text

[Assistant] And in models.py, in addition to an airport class and a flight class, let me create a new class called passenger. Also gonna be a model.


[User] Please transcribe this text

[Assistant] And what properties does a passenger have? Well, a passenger has a first name, which we'll go ahead and make a models.charField.


[User] Please transcribe this text

[Assistant] And passengers also, as we described before, they have a many to many relationship.


[User] Please transcribe this text

[Assistant] With flights. That a flight could have multiple passengers, a passenger could be on multiple flights, and ultimately we need an additional table to keep track of this. But we can think a little bit more abstractly here in Django, and just say that every passenger has flights associated with them, which are a models dot many too many


[User] Please transcribe this text

[Assistant] With flight. So every passenger could be associated with many flights. We'll say blank equals true to allow the possibility that a passenger has no flights, maybe if they're not registered for any flights at all.


[User] Please transcribe this text

[Assistant] And we'll also give this a related name of passengers. Meaning if I have a passenger, I can use the flights attribute to access all of their flights. And likewise, if I have a flight, I can use this passengers related name to access all of the passengers who are on that flight. And we'll see how that'll be useful in a moment too.


[User] Please transcribe this text

[Assistant] The string representation of a passenger will just go ahead and be their first name, space their last name, which feels like a reasonable way of representing a particular passenger.


[User] Please transcribe this text

[Assistant] And now I need to apply these changes. I need to say python manage.py make migrations because I've made new changes to my model. I've created a model passenger in particular. And now if I do python manage.py migrate,


[User] Please transcribe this text

[Assistant] Then now via the admin interface, I can manipulate passengers as well. I can say python manage.py run server to run my web server.


[User] Please transcribe this text

[Assistant] Go to my web server's admin view by going to slash admin.


[User] Please transcribe this text

[Assistant] Go down to passengers, and let's go ahead and add a passenger.


[User] Please transcribe this text

[Assistant] Where I can say, alright, first name Harry, last name Potter, and we'll go ahead and put him on flight one and flight three. Maybe he's on two different flights, for example. And you can hold down command or control to be able to select multiple flights.


[User] Please transcribe this text

[Assistant] And we'll go ahead and save that. Harry Potter has been added successfully. And let's add a couple of other passengers. We'll add Ron Weasley. And we'll add another. We'll add Hermione Granger. And we'll add Ginny Weasley.


[User] Please transcribe this text

[Assistant] So we've added a number of different passengers that now all exist in Django's admin interface. And now what I'd like to do is on the flight page display information about which passengers happen to be on any given flight. So the way I might do that is by going into views.py.


[User] Please transcribe this text

[Assistant] And on the flight page, in addition to giving access to the flight, let me also give it access to passengers. So passengers.


[User] Please transcribe this text

[Assistant] This template is gonna get access to. And we get passengers by saying flight.passengers.all. And the reason we can do this is again, because passengers is that related name. It is our way of taking a flight and getting all of the passengers that happen to be on that flight.


[User] Please transcribe this text

[Assistant] That passenger. Just print out that passenger inside of a list item. And in Django I can say, if the list is empty, let's just have a list item that says, no passengers. Meaning nobody is currently on this flight.


[User] Please transcribe this text

[Assistant] So now, my web server is still running. I can go back to slash flights. Here are all of the flights.


[User] Please transcribe this text

[Assistant] And if I go to slash flight slash one, I now see that I'm flight one. Harry Potter is a passenger on that flight. But if I go to flight two, alright, no passengers are on that flight either.


[User] Please transcribe this text

[Assistant] And now it's been a little annoying that I've had to do everything by using the URL here to be able to go back and forth between pages. I could link to those pages if I want to. And the way I might do that is let's on the flight page add a link.


[User] Please transcribe this text

[Assistant] It's a URL to a particular flight, and the flight route takes as a parameter a flight ID. And so inside this URL substitution here, I can specify use flight.id as the ID of the flight that I would like to use here.


[User] Please transcribe this text

[Assistant] And so now, I've put every single flight inside of a link that takes me to the flight route, but because the flight route requires as an argument the flight ID, I can specify the flight ID here.


[User] Please transcribe this text

[Assistant] And so now, if I go back to slash flights, I now see a list of flights where every flight is in fact a link that can take me somewhere else.


[User] Please transcribe this text

[Assistant] And so now, I can click on any one of those links, like New York to Paris, and that takes me to the flight page. I can click back to flight list, that takes me back to the flight list, click on another flight, and go to that flight as well. So I've now been able to come up with this way of


[User] Please transcribe this text

[Assistant] Linking these pages together by having links in each of the various different pages that take me to some other route as well.


[User] Please transcribe this text

[Assistant] And so now what I might like to do is, in addition to displaying all the passengers on any particular flight, also give myself the ability to add passengers to a flight as well, which feels like a reasonable thing that I might want to do inside of this web application. And so how can I go about doing that?


[User] Please transcribe this text

[Assistant] Well in order to do that, I'm gonna need some new route that lets me book a flight for a particular passenger. And so I'll go ahead and go back to urls.py.


[User] Please transcribe this text

[Assistant] An int flight id slash book is going to let me book a flight for this particular flight id. For flight one or flight two or flight three or so forth.


[User] Please transcribe this text

[Assistant] So how is this view going to work? I'm going to define a function called book.


[User] Please transcribe this text

[Assistant] That is going to, uh, take as its argument, not only the request, but also a flight ID.


[User] Please transcribe this text

[Assistant] The first thing, as with before, is I want to get the flight ID. But remember from before that there are multiple ways that I can request a web page. I can request a web page via the get request method, which means I would just like to get this page.


[User] Please transcribe this text

[Assistant] Or I can request a method via post, meaning I would like to send data to the page. And generally speaking, any time you want to manipulate the state of something, especially manipulating our database,


[User] Please transcribe this text

[Assistant] That should be inside of a post request. I'm submitting some form, some data, and in response to that post submission, you should manipulate what's going on inside of the database.


[User] Please transcribe this text

[Assistant] So we're gonna check when this book route is called upon. If request method is post, then we want to perform some sort of action. The flight in question is just going to be flight.objects.get. Get the flight whose primary key is that flight ID.


[User] Please transcribe this text

[Assistant] And then what I'd also like to do is associated with the form, when someone submits this form to like book a new passenger on the flight, they should tell me what the ID is of the passenger. Like what passenger should I book on this flight? Because those are the two pieces of information you need to know in order to actually book a flight. You need the flight and the passenger information.


[User] Please transcribe this text

[Assistant] So let's assume for now that the information is going to be in request.post


[User] Please transcribe this text

[Assistant] And then in square brackets, passenger. What this means is that the data about which passenger ID


[User] Please transcribe this text

[Assistant] We want to register on this flight is going to be passed in via a form with an input field whose name is passenger. The name on any particular input field dictates what name we get received when a route like this book route is able to process the request from the user.


[User] Please transcribe this text

[Assistant] So we'll go ahead and take that information. Uh, and because by default this might be a string, let's go ahead and convert it into an integer just to make sure we're dealing with an integer.


[User] Please transcribe this text

[Assistant] Is if the request method is post, meaning someone submitted this form via the post request method. I'm first saying flights.objects.get to get a particular flight. Get me the flight with that flight ID.


[User] Please transcribe this text

[Assistant] And then I'm getting a passenger. Which passenger am I getting? The one who's PK, their primary key, otherwise known as ID, is equal to whatever was submitted via this post form with a name of passenger. And we haven't yet created that form, but we'll do so in just a moment.


[User] Please transcribe this text

[Assistant] Now ultimately we'll want to add some more error checking to this as well, like what if someone requests a passenger that doesn't exist, or a flight that doesn't exist either. So there's definitely some error checking that we probably should be doing here. But for simplicity, let's just assume for now that we're able to get a flight and get a passenger.


[User] Please transcribe this text

[Assistant] Well, how do we access a passenger's flights? I can just say passenger.flights. And in order to add a new item to some set, like flights, I can just say passenger.flights.add, flight.


[User] Please transcribe this text

[Assistant] And this will do the equivalent of adding a new row into a table of keeping track that the passenger is on that flight. But the nice thing about Django's abstractions is that I don't have to worry about those underlying details. I don't have to worry about what the structures of the tables are. I can think at a much higher level and just say,


[User] Please transcribe this text

[Assistant] Take this passenger, take their set of flights, and go ahead and add a new flight to that set of flights.


[User] Please transcribe this text

[Assistant] And when all that's said and done, what I probably want to do is return some sort of redirect that redirects the user back to the flight page. So we'll go ahead and return an HTTP response redirect.


[User] Please transcribe this text

[Assistant] What URL would I like to take them to? Well I'd like to take them to the flight route and reverse again takes the name of a particular view and gets me what the URL is and we saw that last time.


[User] Please transcribe this text

[Assistant] And the flight route takes an argument, so I need to pass as an argument the flight's ID. So I need to provide it to the flight route what the flight's ID is structured as a tuple, uh, and that is going to redirect me back to the flight route so that I can see that flight page.


[User] Please transcribe this text

[Assistant] So those I'll need to add as well so that I can redirect the user back to the flight page after they're done submitting the form and reverse takes the name of a particular view as defined in urls.py something like index or flight or book.


[User] Please transcribe this text

[Assistant] And gets me what the actual URL path should be. And as we talked about last time, that's helpful so that I don't have to hard code URLs into my Django web application. I can just reference URLs by their name. And if ever I need to change a URL, I can just change it in one place in URLs.py. And that change is going to reflect everywhere else as well.


[User] Please transcribe this text

[Assistant] So now the next thing I need to do is actually create this form. That what I have so far is just a function called book that is waiting for a post request to be made to it. And when a post request is made to it, then we're going to go ahead and submit this form and go ahead and add the flight for this particular passenger. But what I'd like to do now is actually add that form.


[User] Please transcribe this text

[Assistant] And what I'd like to add here is a form. I'll go ahead and label it with an h2 called add passenger. And we'll create a form whose action is going to be


[User] Please transcribe this text

[Assistant] URL of book. So we're going to go to the book route. And again, if we recall the book route in urls.py, the route with name book, this view,


[User] Please transcribe this text

[Assistant] Requires as a parameter some flight ID. So I need to provide the flight ID as an argument for what flight I'm booking the passenger on. And it just happens to be flight.id because this template has access to a variable called flight. The method of the submission is again going to be post.


[User] Please transcribe this text

[Assistant] And recall from before that whenever I have a form in Django, I need to give it the CSRF token, just for security, to make sure that Django knows it's really this application that is submitting this form.


[User] Please transcribe this text

[Assistant] We'll go ahead and add a drop down list, which you can create in HTML using a select field.


[User] Please transcribe this text

[Assistant] The name of this select field is going to be Passenger.


[User] Please transcribe this text

[Assistant] And the reason for that is inside of views.py, when I get the passenger, I'm looking for inside the post data, inside of request.post, for a field whose name is passenger. And so that is what I would like the name of this dropdown to be.


[User] Please transcribe this text

[Assistant] And inside of a select dropdown, we have a whole bunch of options. Options that we can choose from. And there's going to be one option for everyone who isn't a passenger on this flight.


[User] Please transcribe this text

[Assistant] And so how do I get everyone who isn't the passenger on the flight? Well it seems that right now the flight page only has access to actual passengers and doesn't yet have access to people that are not passengers on the flight.


[User] Please transcribe this text

[Assistant] So it sounds like I need to add some additional context to this template, additional information that we want access to. So I'll go ahead and give this flight access to additional information that we'll call like non-passengers for people that are not on the flight.


[User] Please transcribe this text

[Assistant] And how do I get non-passengers? Well, just as I could say passenger.objects.filter to only get passengers that match a particular query, there's also a way in Django to say passenger.objects.exclude to say exclude passengers that satisfy a particular query.


[User] Please transcribe this text

[Assistant] So I want to exclude passengers who among their flights have this as one of their flights. And so what does this actually mean?


[User] Please transcribe this text

[Assistant] Well, it means that when I render flight.html, there's a couple pieces of information that it should have. It needs to know what flight is being rendered. It needs to know who is on the flight, who are the passengers.


[User] Please transcribe this text

[Assistant] But if I want a drop down where I can choose from all the people who aren't already on the flight, like I would like to register you for this flight, well I also need all of the non-passengers. Passengers except, excluding,


[User] Please transcribe this text

[Assistant] The ones who are already on the flight and get me all of them is what that .all is ultimately saying.


[User] Please transcribe this text

[Assistant] And so using that, I now have access to this variable called non-passengers that I can use as I'm constructing this page. So back on flight.html, I can say for every passenger in non-passengers,


[User] Please transcribe this text

[Assistant] Because ultimately when I submit the form, what I care about getting is what is the ID of this passenger that I've chosen from this dropdown. But of course the user who's looking at this page, they don't want to see people's IDs, they want to see people's names. So inside of the option tag, we'll go ahead and just print out the passenger's name.


[User] Please transcribe this text

[Assistant] And we'll see in a moment what all of this actually looks like in terms of HTML. So now that I've created this form, I'll also need at the bottom to add an input whose type is submit to let myself submit this form to.


[User] Please transcribe this text

[Assistant] Let's now try running this application. It looks like there's a slight error where I said view.book instead of views.book. Views is the name of the module since it's in a file called views.py. And now it looks like my server is running okay. I can go back to slash flights. Let me get one of the flights like New York to London, flight number one.


[User] Please transcribe this text

[Assistant] And alright, name error, name passenger is not defined. This is how Django renders to me errors that are occurring in my Python code. Looks like it just means inside of views.py, I'm referencing passenger, but I never imported it. So up at the top, I'll go ahead and import passenger as well.


[User] Please transcribe this text

[Assistant] Now it seems that my web application is working okay, so now hopefully I refresh this page, I see flight information, I see passengers, and I also down at the bottom now see an add passenger section with a drop down list where I can click on it and see, alright, here are the three people that are not already on this flight.


[User] Please transcribe this text

[Assistant] And so if I want to add, like, Ginny Weasley to this flight, I can click Ginny Weasley, click Submit, and that submits the form, and I'm redirected back to the same flight page. Now Harry and Ginny are both on the flight, and in the Add Passenger list, I see Ron and Hermione. That's the options for me there.


[User] Please transcribe this text

[Assistant] And so using Django's models, I've been able to very quickly build up a reasonably sophisticated application, an application that has models that displays that information to me and lets me manipulate that data. And that data is ultimately stored inside of a SQL database.


[User] Please transcribe this text

[Assistant] And one of the big powers of Django that it really gives to me is this admin interface that I ordinarily might have had to spend a lot of time designing a web interface that just lets me do things like take some person and go ahead and update like what is their name, what flights are they on and the ability to very quickly add and delete and edit the models.


[User] Please transcribe this text

[Assistant] It's something that in a web application could take quite a lot of time to be able to build from scratch, but Django, very fortunately,


[User] Please transcribe this text

[Assistant] Gives all of that right to me. And this admin interface, even though it is designed by Django, it's very customizable in terms of things that I can do on this admin interface if I want to manipulate it in certain ways in order to add additional features to it as well. So we'll see a couple brief examples of this. If I go into admin.py,


[User] Please transcribe this text

[Assistant] Here is my configuration for Django's admin interface. And I can say I would like to configure the admin interface in a particular way. That in a flight, for example, by default, all I saw was like the flight's origin and destination. If I want to be able to see more information about a flight, I can say go ahead and give me


[User] Please transcribe this text

[Assistant] A class called FlightAdmin, which is going to be a subclass of ModelAdmin.


[User] Please transcribe this text

[Assistant] Where I can specify any particular settings that I want to apply to how the flight admin page is displayed. So I can, and all of this is documented on Django's website and you just have to read it to be able to know what configuration options are available to you.


[User] Please transcribe this text

[Assistant] But I can say in the list display, when you list all the flights and display them all to me, what fields should I have access to? Well, go ahead and show me something like the origin and the destination and the duration and maybe also show me the ID, for example. So I want to see all of this information when you load a flight.


[User] Please transcribe this text

[Assistant] And then when I register the flight, I'll say register this flight, but use the flight admin settings when you do so. So I can specify I would like to use these particular settings when you view the admin interface.


[User] Please transcribe this text

[Assistant] And so now, if I go back and go ahead and click on flights, then now in this list display, whereas before I only saw IDs and origins and destinations, now I can configure it to show me all of the IDs and origins and destinations and durations as well, I've been able to configure this display to work the way I would like it.


[User] Please transcribe this text

[Assistant] And there are other configurations you can do as well. Uh, one that I quite like to use is if I want to update my passenger admin. So when I'm editing a passenger,


[User] Please transcribe this text

[Assistant] You can have a special way of manipulating many-to-many relationships inside of an attribute called filter horizontal.


[User] Please transcribe this text

[Assistant] And if I use a horizontal filter on flights, this will just make it a little bit nicer for manipulating the flights that a passenger is on. And again, the specific syntax of this, not as important as the idea that these are all just configurable settings that Django has documented that you can look at to see how to configure the admin interface to work exactly the way you want it to work. And so now if I go back home and go to passengers and maybe click on a passenger like Harry Potter,


[User] Please transcribe this text

[Assistant] I now see this horizontal filter, which is a very nice way of being able to manipulate flights that the person is on. I see on the left a list of their available flights that I could add them to. On the right, a list of their chosen flights, flights that they're already on. And it becomes very easy for me to just take a flight and double click on it.


[User] Please transcribe this text

[Assistant] To move it from an available flight to a flight that they're on and vice versa. Just very quickly being able to control and manipulate these models. And this is all stuff that Django just gives to you right out of the box.


[User] Please transcribe this text

[Assistant] So Django now has given us a lot of features. The ability to represent models very succinctly, a migration method for being able to very quickly apply those changes to our database.


[User] Please transcribe this text

[Assistant] And the last thing we'll take a look at is this idea of authentication.


[User] Please transcribe this text

[Assistant] That on many websites we want some method of authentication, some ability for users to be able to log in and log out for Django to remember who a particular user happens to be.


[User] Please transcribe this text

[Assistant] And what we're going to do now is introduce an application that lets us interact with this authentication method. Because Django has a whole bunch of authentication features built right into the framework that we can take advantage of so that we don't need to rewrite all the logic for how do you log someone in and what does it mean to represent the user. Django has done a whole lot of that for us. So we'll go ahead and create an application to do that now.


[User] Please transcribe this text

[Assistant] Alright, so let's go back into my terminal now, and now I have this airline project inside of which is one app called Flights, and I'd like to now create another app that's going to maintain users inside of this application. So I'll go ahead and run python manage.py start app users, which will just be an app that's going to allow me to represent users. As with before, when I create a new


[User] Please transcribe this text

[Assistant] Application, I'll need to go into settings.py, add users as one of the installed apps inside of this project.


[User] Please transcribe this text

[Assistant] So all the URLs that are associated with my user's application.


[User] Please transcribe this text

[Assistant] Now I'll need to actually create those URLs. So I'll go ahead and go down into my user's application, create a new file called URLs.py, inside of which is the same as what we've normally seen inside of these URLs files. I need to import path, import my views, and then define some URL patterns.


[User] Please transcribe this text

[Assistant] Then I'll create another path that takes me to login, called the login view. And the name will be login. And we'll have another path called logout.


[User] Please transcribe this text

[Assistant] For a function called logout view that will be associated with it.


[User] Please transcribe this text

[Assistant] So let's go ahead now and actually write these functions. We need one function called index, one function called login view, one function called logout view.


[User] Please transcribe this text

[Assistant] So I'll go into views.py and we'll start with index.


[User] Please transcribe this text

[Assistant] As we think about this programmatically, we first need to think about what should happen if someone tries to access this page but they're not authenticated. How would we even find that out and what do we do in that situation? Well, let's say if not request.user.isAuthenticated.


[User] Please transcribe this text

[Assistant] The request object that gets passed in as part of the request to every user in Django automatically has a user attribute associated with it. And that user object has an isAuthenticated attribute that tells us if the user is signed in or not. If they're not signed in, we'll go ahead and HTTP response redirect them to the login view.


[User] Please transcribe this text

[Assistant] And in order to make this work, I'm going to need to, from django.http, import HTTP response redirect. And likewise, from django.urls, let's go ahead and import reverse as well. So if the user is not authenticated, then we're going to redirect them to the login view, where what is the login view going to do?


[User] Please transcribe this text

[Assistant] Well the login view for now, let's just go ahead and render.


[User] Please transcribe this text

[Assistant] Uh, users slash login dot html. Some form where the user can log themselves in. We'll need to create some templates. I'll create a templates folder inside of which is a users folder. Inside of which we'll just create a basic layout as we've done multiple times now.


[User] Please transcribe this text

[Assistant] This is again going to be the general structure for pages in this app. Title will be users and the body will just have a block called body that I can later fill in with other content.


[User] Please transcribe this text

[Assistant] And now that I have this HTML layout, I can go ahead and create a new file called login.html where login.html will extend user slash layout.html and inside the body block,


[User] Please transcribe this text

[Assistant] I can just display an HTML form. So I can say something like, I would like for there to be a form.


[User] Please transcribe this text

[Assistant] Whose action, when I submit the form, let's go ahead and still go to the login URL.


[User] Please transcribe this text

[Assistant] But let's do so using the post request method. Again, I'm logging in, I'm submitting a form. Generally, when you're doing that, you want to submit form data via post, especially in the case of username and password, because if you do this sort of thing, uh, you don't want the username and password to be passed in as get parameters because those show up in the URL.


[User] Please transcribe this text

[Assistant] Our form will have our CSRF token for security as before, an input whose type is text, whose name is username, and just for user friendliness, let's give it a placeholder also of username so the user knows to type in their username here. We'll also have an input whose type is password.


[User] Please transcribe this text

[Assistant] Whose name is also password. And when an input's type is password, that just means our HTML will know in the browser that Chrome or Safari or whatnot will know to show the password as dots instead of as characters. And we'll give that a placeholder of password.


[User] Please transcribe this text

[Assistant] And then an input of type submit whose value is login. So we now have the ability to log in.


[User] Please transcribe this text

[Assistant] So if we go ahead and run this program, python manage.py run server, we should see