Welcome everyone to this lecture where we continue setting up our overall project with some models.
So in order to continue setting up our library, we're going to need a model to actually understand
what a book is.
Things like the title of the book, the author, maybe a summary or ISBN number genre.
And then speaking of that book and the genre, we can actually connect genres as its own model.
So we can have genre as a model, and we can also have something like language as a model.
So we're actually going to show you how to connect genre language and book models together.
So essentially the genre of a book will actually be a reference to a genre model instance.
Then we'll also have author be a model in itself.
So, for example, while a book can have an author, the actual author object would be something more
akin to a name, maybe a date of birth, date of death, books, etc. And then we can also have a book
instance, which is a specific physical copy of the book.
This might be the most confusing part, so let me hone in on it right now.
Users of our library will eventually be able to check out a book instance, and we can have multiple
book instances of the same book.
For example, while you could have Catcher in the Rye be a book, you can have multiple physical book
copies of Catcher in the Rye.
That way, more than one person ends up checking out Catcher in the Rye.
So those would be unique books.
That is a unique instance of a physical Catcher in the Rye novel.
So let's head over to our Voice Code editor and continue on.
All right, so here I am back inside our project.
I'm going to go to Models Dot Pi and begin to create our models.
So this basically is just going to be typing in certain models that pi file.
Be careful not to commit any typos here.
You can always reference our code.
I'm going to start off by actually creating the genre model first so you can see how we later connect
this to the book model.
And there's different ways of connecting models together.
We can do something like a foreign key or even something like a many, too many.
So first off, let's create a new class for this model called genre.
And we inherit from models that model.
And then I'm going to say something like this is a model representing a book genre, so we'll have an
attribute for name of the genre.
And then we're just going to say something like Models a character field and let's give the same max
length of, let's say 150 characters.
Okay.
And then if you actually want to print out the genre, let's give it a string representation.
So we'll say string peasant self here.
And this will simply be something like return self taught name.
Okay.
So all we're doing here is setting up our class, genre and names equal to models, not character field.
And right now you'll notice a lot of this text is white.
So let me just quickly choose a different color scheme so we don't get confused.
All right.
There we go.
Just switch the the color scheme that we hopefully a couple of things are different colors.
So it's clear what's actually happening as far as what's a class call, what's a function call, what's
a method, etc..
So we have our genre class.
Now let's set up our book model.
And be careful again if you're indentation here.
So the book model is essentially defining the single book title.
You can think of it that way.
Obviously, title is actually an attribute of a book, but this is not the book instance that we'll
talk about later.
So here we're going to say.
Class book.
Models that model.
And here we're going to say title is equal to models and we'll have a character field for the actual
book title.
So I'm going to say like Maxlength is equal to take 200 characters doesn't really matter too much for
our simple examples here next we want to do is have an author.
Now I didn't mention later on we'll actually be creating an author model.
So let's reference it here as a foreign key and then will actually build out that particular model so
we can get the full reference.
So essentially what I'm going to do is say that you have an author here, but I actually want book and
author to be their own models.
So this author is not just a simple character field.
Instead, it's actually going to be linked to a specific author.
So we're doing this story for key.
Why do this?
Well, an author could write multiple books, so be nice to have our own little database table of authors
and then we can link them to the books that they have written that we later on, if we wanted to add
more functionality, I could look up, Hey, this author and all the books they've written, sort of
the same models, not for anarchy.
And then we're going to say author.
And then we can say a method on delete.
Is equal to models that set null.
And basically what this means is that you have to decide at a certain point when you start linking models.
What happens if I delete this book?
Would you also delete the author or would you delete the book if you happened to delete the author one
way or the other?
So there's different ways of doing this.
And one way is to set models to set now.
And essentially what happens here is that actually allows a database to store a null value if no author
is selected.
And that happens to mean that if you collect and delete two equal models that said no, that's actually
a set the value of the books offer field to NULL if the associated author record is deleted.
This is just a complicated way of saying that if for some reason your book exists but somebody x only
deletes the author.
It's not like the book suddenly disappears as well.
You just are going to say, Hey, if you happen to odd delete the author, you will set it as null for
this book.
So it's kind of like the English translation of this code.
So again, for the author on deletion of the author for this particular model, you'll set the author
as null for the book.
So hopefully that clarifies it.
There's also another default behavior, which is Cascade, which means that if the author is deleted,
the book would be deleted too.
And sometimes maybe depending on the situation, you want that.
So obviously there's something going on if you want to delete this author and suddenly delete all the
books along with them because maybe it was a mistake.
Then you may want to actually cascade that down so that actually end up being a delete is equal to models
that cascade.
But setting all is probably more appropriate for what we're doing here.
We'll continue to build out book, but since I didn't mention that we're connecting this to an author
model, let's quickly jump to the author model.
So keep in mind more to come here for book, but let's set up this author model.
Or C class author.
Models not model.
And then let's give them a first name.
So models the character field.
Let's just say 200 for the max length.
Let's give them a last name as equal to models.
The character field 200.
And then, let's say date of birth.
Date of birth is equal to models, and this probably makes more sense to be an actual date field.
So have that be a date field and we'll go ahead and say NULL.
It can be true if you don't happen to know them and will even let them leave it blank if we want to
say blank is equal to true as well.
Okay.
So you could keep adding more information from on to like date of death, etc..
Something we haven't seen before is adding a little bit of class here that can help us dictate behavior
inside the admin view.
Like what you want these sorted by or ordered by.
So I can say ordering is equal to.
And then you can have a list of how you want these ordered when you actually visit this or request this
back.
So I can say I want these ordered by last name.
Karma.
First name.
Okay.
And then finally, we're going to create some method calls here to actually define some URLs.
So essentially it would return the URL to access a particular author instance.
So the way this works is you create a method here called get absolute URL and you'll notice it actually
autofill for me.
But it's essentially going to be a reverse call.
And instead of model detail, I switch this to say author detail.
So I'm just switching for the actual name of the model.
And then the keyword arguments is going to be here.
You could say peak.
Peak is equal to self peak.
And I should point out that this does require a reverse call, which means up here I need to import
that an essay from Django thought URLs imports reverse and we'll see that more later.
But it's essentially they're saying, where's the URL that I could actually grab this author's detail
from?
So we have our author class.
Last thing I want to actually mention here is how to get the string representation.
So say str here passing self and we'll just return.
You can use f string literal formatting.
I'm going to return the last name.
First name so I'll say last name.
This should be self last name.
So if last name.
Karma.
Self first name.
And put that in.
Okay.
So that just returns, you know, something like last name, comma, first name, if you ask to actually
print out that author.
So, so far, so good for the author.
You could keep adding more features if you wanted to.
But let's head back now to book.
Here.
And now that we've set up author, we can see what's actually happening here.
So if I delete this, Arthur, this book survives.
It just sets the author to know.
Now let's continue.
What else do we want for the book?
Maybe you want something like a summary.
So, like a it's a description of the book.
So let's go ahead and say summary of the book.
Equals models.
This probably didn't make sense as a character field because it's longer.
So we'll say something like, What's a text field?
And let's give it a longer maxlength like let's say that 600 or something with 600 characters, maybe
that's too little, but not a big deal.
And then if you want, you can also set this to be nulls equal to true or whatever, but we'll leave
all the defaults there.
So we have a title and author, a possible summary.
Then let's go ahead and give this an ISBN number.
So if you're checking out a book for the library, you know what I'm talking about here.
It's not just Google Search, one ISBN number, essentially unique identifier for this book.
So say character field and this is just going to be.
ESPN.
And let's give this a.
Max length of I believe officially it's only 13 characters long and this one does have to be unique.
We can't have multiple books of the same ISBN and if you're not familiar Price mean it's essentially
a unique code to identify the books in the world.
If you've heard of the Dewey Decimal System.
All right.
The last thing I want to do is actually connect this book to a genre.
But unlike our simple model, where a book only has one unique author, technically there are cases
in the real world where a book could have multiple authors.
But in this case, we're just considering a book having one single unique author for genre.
Let's show you how to connect multiple genres to a book.
Maybe a book is both mystery and sci fi genre.
So the way we do that is we actually classify this as a many to many connection, essentially saying
that many books could have many genres.
So for example, again, a book could be both a sci fi and a mystery novel.
So let's go ahead and set that up.
What I'm going to do here is set this up as a many, many fields.
So we'll come here and say genre.
Attribute is equal to models not and they'll say many to many field and here we connected with the genre
class we created earlier and that's how you can connect it so that a book can then have essentially
a list of potential genres.
Let's also give a string representation for our book.
I'll say def.
That's tr self.
And let's say it's going to return Self's title.
It's by the simplest way of doing this.
And let's also have it get absolute URL.
It's going to return the URL to access a record for this book.
So we'll say def get absolute URL.
Self.
And again, it's sort of model detail.
I will say this is book detail.
Notice I'm just using tab here.
It's auto complete.
So this is book detail and then we can have the identity be that.
All right, so that's looking good.
So next we have the actual book instance.
So I have a book, a genre and then an author.
And that's what I'm going to do is set up a book instance model.
Remember, this one is actually going to be unique.
So in that case, what I'm going to do and I'll do it here for now, I put this at the top is have you
you ID.
Which is a unique identifier generator.
So essentially it will just generate a unique ID.
You'll see why we do this in just a set.
So we're going to say class.
Book instance.
Instance.
L.S. models that model.
And then from here, we're actually going to specify an ID attribute that is model's dot u u IED field.
Okay.
So essentially what's happening here is the book instance represents a specific copy of a book that
someone might borrow and includes information maybe about whether the copies available or what date
it's actually expected back.
So we should know, hey, this particular book is actually checked out for the library.
So some of the fields we're actually going to be familiar with.
One of them, however, needs to be a representation of a specific copy.
So for that, we can just essentially borrow this from the UUID Field Library.
So we'll say this is a primary key is true.
And then we're going to say default is equal to and this is what we use that import you, you ID, you
id4.
Okay.
Oops.
Make sure you do it.
There we go.
Since we imported that.
And then we'll connect this to a book.
So say book is equal to models for key.
Kind of makes sense that a book instance should have a unique foreign key relationship to a single book.
And then we're going to say on delete.
So what happens when you actually do a deletion of a book?
In this case, maybe you want to do something like a restrict call.
This essentially restricts you from deleting a book if you still have a book instead.
So you have to delete all the book instances first before you're allowed to delete that book.
So that means I'm going to say all delete is equal to model's dot restrict, essentially saying, hey,
if you have a book in the library or checked out and you try to just delete Catcher in the Rye, you
have to actually take care of all those book instances first.
You have to pull those out first before you can do a general book from your database.
So we're going to restrict that, and then I'm going to say, no, all is equal to true here.
And then I think that should be enough.
Maybe we want something like an imprint on the book.
Let's say imprints.
Attribute is equal to models, not character field.
Let's give it a max length.
Let's say 200 such essentially can imprint something out of the book.
And then more importantly, what does it do back?
So this makes sense for it to be a field or say, the field.
No is equal to true.
So if it's null, that means it's in the library.
And also, let it be blank if we just want to leave it blank.
Okay.
So we can have an attribute actually be a selection of something.
So you can say, hey, what's the actual loan status for a particular book instance?
How would we do that?
Well, I can create an attribute that is essentially a tuple here.
So for example, I can say loan status is equal to a couple of tuples where I'm going to have a parent
here.
We're going to say M for maintenance.
Then we're going to say, Oh.
For.
On loan.
We're going to say if it's available.
And then I'm going to say are.
If it's reserved.
And then finally, let's now that we have this lone Sarasate tribute, we can use that to actually create
a general status, that tribute.
So say this is the model's character field and this will show you how to construct a field based off
other attributes.
So, for example, the max length of this field is just going to be one y1 because we're basing it off
m, o or r.
So the max length is one.
The choices.
Sorry about that.
The choices here.
Are going to be your loan status, are your choices.
It can be blank if need be.
The default behavior will be maintenance.
So say default is M.
And that is your status.
Let's put that all in one line there so you can see it.
There we go.
So that's the status of the book.
And then finally, if you want, we can set up a meta class for the ordering.
So Saint Mata ordering here is when it's due back.
What's the mixture?
This actually matches here?
Do back.
Okay, perfect.
And let's actually create an instance representation of how to actually print out a book here self.
And then I was going to return.
Let's see if.
Died.
And then it's probably also applicable to print out the actual book title itself.
So it's that title.
So I can't just say self that title because technically book instances don't have titles.
However, book instances do have a book and the book is a foreign key, which in turn actually has the
title.
So the way I would reference that is I would say soft dot and then I would say self.
That book, the self, that title.
Okay.
And that's how you can actually grab the title based off a foreign key relationship.
So again, it's going to say this book instance is linked to a book.
Then grab that book's title in order to print it out.
If you ask for a book instance because we don't just want the idea, it's just going to be a random
number that we won't recognize.
It'd be nice to actually see the book title there just in case.
Now, I did mention maybe you want a model for something like language.
So let's imagine we're starting to expand the library and somebody donates a book in Spanish and now
we have the same books, but now they're actually in different languages.
So how do we do that?
It probably makes sense to actually set up a language class and it would kind of operate similar to
genre, but we would later on add it to a book.
So let me show you.
What this would look like.
So I'll say class.
And I'm going to now make a new class called My Language Class.
Models that model.
And it's gonna be pretty simple.
She's going to be a name.
So the name of the language should be a character field.
Let's say Maxlength is equal to 200.
So this is something I would say like Spanish, French, Japanese, etc. and then can be a simple string
representation here to just return self thought the name of the language.
Okay, the question becomes what's the best way to connect this language to our present book model?
Well, in this case, a book is probably just in a single language.
It wouldn't make sense to make it exactly like genre, because typically when you're thinking of the
language of a book, it's not going to be both in English and Japanese.
Now, maybe there's actually books on learning a language, which would be tricky, but in that case,
you'd probably want to have it in the learner's language.
So that is to say, if you have a book that teaches an English speaker how to speak Japanese, the language
of that book should probably just be English, not both English and Japanese.
So in that case, we would just come here and make it a foreign key.
So I would say language and helps.
That should be lowercase.
The language of the book is equal to models that foreign key.
And then I would think it up to language.
There we go.
So I would have each book now having some sort of language.
Now the question is, what do we do if we were to delete a language?
So oddly, plie makes more sense to just set this as the also, I'll say models that set null and we'll
say null.
That can be true.
Okay.
So that's how you could add in a new field for the book.
So save all of that and let's go ahead and run some migrations.
Remember, we have to first make the migrations and then we need to actually migrate.
So first off, let's check here.
Looks like we have some hints telling us we maybe have something up.
So in the author last name, character fields must define a maxlength attribute.
So let me come down here to author, and it looks like you just typed in 200 instead of the maxlength.
I'll fix that now.
So Maxlength is equal to 200 and we'll set that up first name there.
And so then on book author it says The field specifies Anderlecht is equal to set nul but cannot be
null set null equals true argument on the field or change the oblique rule.
So we'll come back to author or excuse me, book author.
Here it says set null.
Which means I should say null can be true.
There we go.
So now we'll go ahead and save that.
And it looks like there was no complaints.
So did those checks for us, which is really cool that it's actually doing those checks even just on
saving.
So what I'm going to do now is I should be ready to actually run the migrations.
So let me do controls, see here and say up here I'm going to say Python managed that py make migrations.
Enter.
Looks like it's all working though.
I'll say python manage that.
Pi migrate.
Hopefully we didn't permit any typos there, but it looks like everything worked.
Okay, so we talked a lot of code.
If you're starting to get errors here, definitely.
It's kind of thing where you probably want to just reference our provided code.
Okay.
Thanks.
And I will see you at the next lecture.