Hello, and welcome to our walk through for Django for Everybody. So the walk through that we're going to be doing is the walk through for the my articles which is really focusing on the notion of owning rows in a model. What I've got going here is I'm logged in twice, I'm logged in one with the user ID of one and the other is the user ID of two. So let's just do a quick demonstration of what really owning rows in a model is. So here I'm logged in as my first user and now I'm logged on, I'm using a separate browser because this is Safari and this is Firefox. You can't just do this with tabs because the cookies are shared between tabs and so you can't. You can login and logout, I want to just be logged in simultaneously. So delete these tabs, refresh. So you'll notice that the Edit and Delete buttons show up differently for different users. So not because this row in the table lawn mower belongs to this user, user number 2, and these two rows belong to this user. So if I take a look at administration and I go down into Users, I can hover, figure out that csev is two, you can see at the bottom there and dj4e is user 1 and csev is user number 2. So those are the primary keys in Django's user table. Now, if I go and I take a look at these articles, you will see and this looks a lot like if you were looking at say your autos, you use these rows or the models in articles. If I look at lawn mower, you see that there is a title, some texts, and the owner is a drop down and that's because this is a one-to-many field. This is a one-to-many field between the articles and the users. Then if I switch to a different, so that's csev. So csev owns the lawn mower. I'm logged in as DJ4E here, no, here, that's my name on DJ4E. If I switch to trombone, we'll see that that one belongs to dj4e. Now, I can sit and edit this in admin but that's not the point, the point is to build a software. If you'll notice when I create a new article, it doesn't ask me what user it was. So this is where you would say dodge or whatever when you were doing cars. So this is like a race car, slightly used, neon. So now I have another one, and so the key thing was is it looks like a create from things we've done before. Now if I look at my articles, here's this but somehow magically this owner field is populated and that's the essence of owned rows. As we've gotten a column and these are marked and in our code we know the difference, for example, between things we own and things we don't own. So if I hit "Refresh" over here, there's a slightly used race car, but I can edit it. So that's the ownership. Now, I don't know where to start, there's a lot to cover here. Where will I start? Let's start with running this locally and no effect while this is there. That's not above. So this just looks like your autos. If you look at it, it looks pretty much like the autos, and then the mileage, and price in there or something. The only thing that's really different at all is this, there is a foreign key known in your autos, you add a foreign key to max. The key difference here, the only thing that's new is this idea of where the foreign key is pointing at. Now, the problem is in Django, there is actually a table that all these users live in. Now, I can probably come over here and type.tables and I can see it. I think it's probably here. So let's just try saying select star from auth_user. So we should see a bunch of rows. So they are my users, csev, so it jumped together in dj4e. So this is row 1 for dj4e and csev. So there is a table in the model, the difference is just we're not allowed to know that this is the user model in the auth application. So what happens is, we have to let Django tell us what the name of that model is. So we go into settings, which is settings.py actually. We're going to pull in the settings.py and the default is Auth_user model, and that's the name of the model. So this is a foreign key to a place that we don't exactly know but Django will tell us. Put in a string here, if we were to print this out, we would see what that is. That's just a string, but it's not a string we mess with. On_delete cascade, that's just normal, that kind of parent row, the one row is in users. If you delete a user, that means that all of the rows that belong to that user will get deleted. It goes on on_delete cascade. I'm choosing at as the model. So you see I created_at, if we go into that back into that, you see all of these things. Now Admin doesn't show, it's pretty smart knowing about created_at and updated_at, so don't bother doing that. It actually updates them automatically. So it knows something about created_at and updated_at in Admin, okay? So that is our model. If we were to take a look at my arts article, you will see that there is a foreign key right there. There's a foreign key and if we say select star from my arts article, you will see that there is a foreign key in there. So this row belongs to User 1, this row belongs to User 1, that row belongs to User 2, and that row belongs to User 1, which is perfectly reflected here. So now I am User 1, so I can edit three of them, now I am here with User 2 and I can edit one of them. So I'm editing the ones where I own it. So ultimately, we're going to write a bunch of code so that these numbers are properly updated. So when you add the article, it works the way you want it to work, okay? So let's just take a look at URLs.py but it's pretty boring. This looks just like autos. I probably hoisted up success URL here, put that in the as view as a parameter. So that makes my views even simpler. Myarts:all points to that view. I think it actually is kind of prettier to put it in here because this is sort of a URL place. So it's not in my view, so that makes my views really succinct. So it's like what you did once you got your autos down to like just using the generics. So I have a list, a detail, a create, an update, and a delete. I have a model called article, which I just showed you. I am going to reuse some general purpose views for owner kinds of rows. Now these are not from Django, these are from me. I made them and now I'm using them. So article list view extends owner list view. Then I can put all my things in there. The success URL actually, I don't need that here, but for CreateView, I do need a success URL. But for CreateView, that success URL comes right from here. So I could have put it either here or I could have put it here, for me, after a while I think this is prettier because now I can look at all the names of my arts, etc. So that's nice. Okay, so here's views. We're going to come back to this. All the brains of this operation are in OwnerListView, OwnerDetailView, CreateView, UpdateView, and we'll look at that last. So that's where the hardest part is. But let's first look at the template. So here's the template. This looks a lot like your autos. The only real difference here is that, this edit and delete button is inside of end if state. So it's article_update, article_id, article_delete, article_ID. That's the same, you've done there, right? It says is, if article.owner is equal to the current logged on user, article.owner is one of the article lists and that's just one of the fields in the model, which happens to be a number. But, we're given this user for free, right? It just hands us user and so we can compare it. So if this is one that we own, we show this link and if it's not one we own, we don't show the link, right? So we don't show that link for the ones that we own. Now, I hope by now you realize that we have to also protect, right? So if this is number four, right? If I click edit number five, but what if I just change this to four? Just not putting up the link does not mean that we can't have someone go to that link. So I'm cheating by putting in this link, but this is going to blow up. So we'll show you how, just because you don't put the link up, doesn't mean that people can't go to the link. They can guess what the link is. I just did that. I went to an article I could update, I noticed the primary key of one I could not update to be four. Then I went to five, and then I just edit it, changed it to four and I attempted update four. So it's not good enough just to not show the link. That's actually not security, that just is prettiness, usability. Don't show a link if it's going to blow up if you click on it. So it's not really protecting us. This if statement is not really protecting us from clicking on, or attempting to go edit, or delete. It's just not showing if it's not going to work. Again, article.owner is just a column in this model, and user is the current logged in user. So what we'd seen before is I would create a view and then use it in my urls.py, and it would extend another view. So now it's time to take a look at where this view is being defined. So here's our GenericView, generic ListView, DeleteView. These are the generic ones, and all I'm really doing here is I'm creating a class called OwnerListView that extends ListView. Now, it pulls in everything that ListView is. You'll notice I've added nothing to it. I really could, because the ListView doesn't really care. It's not really doing anything other than the fact that it add values in the models. So it's going to come in. So I could have made this be ListView, but I just want it to be pretty. I want to make it so that I could just say OwnerListView, OwnerDetailView, and so you'll notice that I'm not making any changes at the moment of inheritance. So OwnerListView is exactly the same as ListView, and OwnerDetail is exactly the same as detail. I just did it to make it pretty in case later on maybe I want to add some. But now, we get to OwnerCreateView. OwnerCreateView is something that matters a lot. So there's two things we've got to do for OwnerCreate. So let's go ahead and start to add an article. So the first thing is there is no field here for which user it is. It would be silly and I can actually mess this up. So if I go to CreateView here and I add user, then if I hit "Refresh" on the CreateView, now come on, back up. It's not user, owner. So if I add it to that list, and part of this, what's going on here, is there is both a model and a form. This fields equals is informing the form, and the form is the user interface. So look at this. I'm allowing the user to specify it and now they can set the owner, pretty convenient. Well, that's not what we want. So that's why in this CreateView, we say, don't let them set the owner, I don't want them to see the owner because it takes a while for this thing to restart. Now it's restarted, and I can hit "Refresh". So it's blowing up, it was just because I was coming here too fast. What is that? Don't know what that is. So go back to the views. Maybe I have some tiny little bug, I'll dig through that bug later. It's working, it's by passing the OwnerCreate so I'm pretty happy. So remember that there are two sides to this. One is the database side, and that's what the model deals with, and then there is a form. So this ListView, if you recall, once we tell it the model, it actually makes a form. So in this CreateView, it's making a form from article, copying all the fields in article or the fields according to this little list. So that's why we're doing it. So the key there is explicitly not putting owner in there and we're not putting created_at or updated_at. If I wanted to put created_at in here, say, hey, let's show them created_at. Let's refresh. So again, it's trying to go from the article model to make a form and it's not an editable field, so it's mad at me, so I'll go back and fix it. I'm sorry. You get the idea. It uses this list of fields to make a form. The same for article and for update. In fact, the update and the create are so equivalent that the template for them is shared. It's basically, we'll talk about crispy tags separately in a different little video. The form is the same, the difference is when the update comes, there is already data in it. That's the only difference between a create and an update. It looks exactly the same, but update has data in it, a create has no data in it. So the code between create and update is super equivalent, very similar, and the template is similar as well. So there we go. So we got CreateView, DeleteView, etc. Now, I'm going to focus on CreateView. The key to CreateView is now in owner.py. Here's our form. That's pretty straightforward. In owner.py, this CreateView now has a little bit more to it, the ListView and the DetailView just inherited. So the first thing is that CreateView has a LoginRequiredMixin and that's because if you're going to create it, you need to be a logged in user. But to view it, you don't actually have to be a logged in user. Let me log out here. So now I'm not logged in as anybody, and so I can see all these. I can't edit any of them. I could login if I want. A DetailView also works, so I'm completely logged out here, but I add article. So Add Article is protected by login. So OwnerCreateView, LoginRequiredMixin. I do this because I don't want to trust the user who's writing this view to put the LoginRequiredMixin here, because I am writing code right here that depends on the fact that this person is logged in. So this is like a guardian pattern. Again, I'm putting this in here so I don't end up with tracebacks inside my code. I don't want it. If I didn't put LoginRequiredMixin in OwnerCreateView, then in the views.py, they forgot to put it in an ArticleCreateView, then this code would blow up. It would trace back at when I try to set object owner to self request user, it would just blow up. So I'm extending CreateView which is inheriting all the functionality, and I'm only going to override one method on this object orientation. You got to go read all the documentation, this documentation right here. I'll show you that documentation. This documentation is hard to find and I'm sure I helped myself by doing some stack overflows. So that's why I put little notes at the bottom of the file, things that took me a long time to find. So this FormModelMixin, and that is, what they're really doing is they're giving us for these editing fields the update. They're saying these are the functions that are in this and I can override them. So the one that I'm overriding is the form valid, and what that does is it basically says, here's your form, save it to the database, and set the current object for view, and then redirects to get_success_url. That's its job. Except that right before its going to save the form instance, I want to do something myself. So what I'm doing here is I'm saying, and the form is what's being called as the parameter, which is the form that has been pulled in from the post-data and handed to me. So what I'm going to do is I'm going to say, save it, but don't save it to the disk. That's what commit equals false means. Don't save it to the database, just save it into this variable object. Then I'm going to set the object owner. I'm simply going to copy the current logged in user into owner, and then I'm going to set it to the database. Then what I'm going to do is I'm going to call the original form valid. Passing form in is a parameter that's in this class, and that's really not going to do much, because it knows that it's already been saved, so it's not going to save it again. Then what it's going to do is, it's just going to do the redirect to the success URL. So this is rather late in the process of CreateView, it's been validated, it's checked for bad data, etc. So this is right before the redirect happens. So at a high level, my whole goal was to pause the saving of this data to the database and sneak the current login user into the owner column, and then be done with it. So that's the basic overriding. I'm really extending form valid to cause my code to be called right before a default code is called. So that's on a [inaudible] , and that's how once I add an article and put some stuff in, and I submit, right as I submit it and right before it's saved, there is a little field called Owner that's going to be updated, and it's there. So the Owner field came from this code. Now I don't have to. I could have put this in this view.py, but no, I got this really awesome creatable thing. I can write really cool code. I'm going to make hundreds of views, and we will throughout the rest of the semester do this over and over and over again. We're never going to change this file again. So now let's talk about Edit. So there's two things. So here we're going to load Article 6, and then we're going to put out a form that has all the stuff. So the first thing that's got to happen, in OwnerUpdateView is we got to check to see if this belongs to the current logged in user. Remember when I tried to go to whatever it was, 4 here and it blew up, this is the moment where I'm going to protect it. So if we take a look at the moment where it's loading the model, we have a link to that, then go populate, let's go to stackoverflow here. This one, I've got one stackoverflow [inaudible] at 10 years prior, good one. Middleware, somewhere in here, I should make that link be a better link. Oh, I like this one. I'm going to put a link in just to this one here. Straight to that one. It's telling us what to do. You see, I just borrowed this right there, form_valid. Oh, wait. No. That's was the Create. Sorry. Can't find quickly where I can do this, but queryset. So queryset is called when it's loading ID number 4, so it's going to do a load. So queryset is not the actual load, but it is the query to the database that we're going to do. So what I'm going do is I'm going to tweak the queryset, and this query set is probably going to say, "Show me where ID equals 4." So it's going to say something like, "Select from articles where ID equals 4." If I just did the normal queryset, it would work, but I'm going to change the queryset. So what I'm going to do is I'm going to call the default get_queryset in the superclass, which is the DeleteView class, and that's going to say, "Query where the primary key equals 4," in this particular case. But then what I'm going to do is I'm going to add another filter. This is like and, and owner equals the current logged in user. So number 4 is owned by user 2, but our logged in user is 1, so this is going to be and logged in as user 1. So when it does the query it says, "Give me the thing that's ID equals 4 and user ID equals 1", it's going to get no records. As the delete code or the update. Am I looking at delete? Update and delete are the same here. Before it does an update, it has to load the old data, and I have made it so that if you're not loading data on something that you own, then it's going to give you a 404. It's like that wasn't found. Now, 4 does exist, it just doesn't exist for the current logged in user, but 5 does, and it does belong to me. Now, the other thing is, it's going to call get_queryset again, New Stuff, XYZ 123. So when you submit it, it actually is going to call get_queryset one more time before it actually stores the data. Let me show you, this will be tricky. I'm going to try to mess with it on 4. I'm going to try to change 4. I'm going to go into "Edit" screen and I'm going to "Inspect Element," and I'm going to somewhere in here, "Find." Where is the hidden? Input type hidden. So that is the input type equals hidden. No, that's the middleware token. That's not the one I want to change. Where is that? Because it's in this URL. I don't think if I change this to 4, it's actually going to work, but let's try. It's probably not going to work, that one work. But the idea is eventually someone could mess with that post so you still got to protect it, right when that data is being modified, it actually does. It runs this code again and it reads the thing, and if it can't read it, then it won't let you update it. So that protects you from people breaking in and attacking there, and the OwnerDeleteView is the same thing. If you go into delete, it does a get_queryset, and I add this filter to say, and it has to belong to the right person. So if I tried to delete article 4, it says I can't load article 4. But if I come over here, and I'm going to log back in. So this one I think was csev. So I can't delete number 4 here, because it hides it which is crappy, but there it is. It's deleting number 4 any way I go. A lot of stuff. So here's the thing, we're going to use owner.py over and over and over again. We're going to write simple and elegant views, and all we have to do ultimately, any model that we want to have this owner feature with, we add an owner column to it. Then we have the views, extend an owner view, and then everything's taken care of after that point. We're not going to change a line in this. It's really cool. We're going to use in project after project, and table after table after table, because this can apply to different models. It's just this one happens to be applying to the article model. So I built a super generic owner capability that I can use over and over, and just take your time, watch this more than once. Review object orientation, figure this out. It's hard for me when I'm teaching to explain why object orientation is cool. Object orientation is cool because it can let you write these super elegant and very reliable. The fewer lines of code you write, the more reliable it is, but the harder it is to understand because the magic is here in this object-oriented pattern. Again, it took me a long time to write this stuff, but now it's really gorgeous and really reducible. So keep thinking about object orientation. We're going to be doing a lot going forward in terms object orientation. So I hope this helps. Cheers.