-: Hi guys and welcome back.
In this video we are going to be separating our code
into models so that we can code more easily.
Basically we're going to be creating classes
out of the entities that our code deals in
so that when we are dealing with those things in our code
it becomes a little bit easier.
We're gonna explain everything that goes on with that
throughout the video.
So, let's get to it.
At the moment, we have our app.py
dealing with certain things.
Those things are, for example, polls
options, votes, potentially even users.
And often, in programming,
when we're dealing with entities,
as we call them,
it can be helpful to create classes for them
so that thinking about those things
as individual entities can become a little bit easier.
So, models are things that our programme deals with internally
and the purpose of them is to make it easier
for different parts of our application to communicate
and also to make it easier for us to read
and reason about the code.
At the moment,
this poll's variable for example,
the database.get polls,
is a list of tuples, it's not a list of objects
that we can interact with
and potentially ask them to do stuff for us
by running methods and stuff like that.
So, that's what we're going to do throughout this video.
In my code I'm going to create
model classes for poll and option.
I consider votes to be sufficiently simple
and encapsulated within options
that they don't need their own class
and our use of users at the moment
is reserved to the username string
attached to a vote
and we're not gonna create a model class for that either.
If we were storing more information about users or votes
and we wanted to do a few more things with them
then we might reconsider this.
But for now, let's go ahead and create our models.
Python directory.
We're gonna call it models.
And in here we're going to create our poll.py Python file.
So we'll do poll.
So let's begin writing a class
to represent everything that our application
wants to do with polls,
including the data stored by a poll.
I'll create the poll class,
and by the way let me just hide away this project there.
I'll create a poll class and then we're gonna add
the init method in it
and the polls have three properties:
a title, which is a string,
an owner, which is a string as well,
and potentially they have an ID property.
I'm gonna call it underscore ID, which is an integer
and defaults to none.
The reason it defaults to none
is that if it doesn't get passed in
when we create a poll object,
we're going to assume that this poll
hasn't been saved to the database yet
and we're still waiting for the database
to generate the ID for us.
So we'll do self.id equals underscore ID,
self.title equals title, self.owner equals owner.
Often for these classes
we want to create a repr dunder method
so that when we are debugging
and when we're printing stuff out
it's a little bit easier to see
what the object that we create represents.
So we'll do a repr,
and what this is gonna return is an f string
with the poll and then the self.name.
And what I'm gonna do here
is I'm gonna put an exclamation mark r
and that is gong to print out self.name
but it's gonna make sure that it looks like
what it would have to look like
for the string to be valid in Python code.
Basically, it's gonna put
the quotation marks around it as well.
Then we'll do self.owner.
And by the way that should be self.title, not self.name
so I will fix that in a moment.
And self.id.
(drawn out) self dot ID and r
There we go, just like that.
This should be self.title.
Now what this is gonna print out essentially
is poll and then the title, the owner, and the ID,
which may be like, I don't know, one.
And you can see that this here,
we can use to recreate any poll object,
and that is the purpose of the repr method.
It should return a string
that can be used to recreate the object it represents.
Next up, we're gonna add the methods for the main things
that we want to do with a poll.
And one of those things might be
to save it to the database.
So we'll do save
and then we're gonna do connection equal
and we're gonna have a function
called create connection here,
I'll code it in just a moment.
The new poll ID is gonna be database.create poll
we're gonna pass in this connection self.title, self.owner
then we're gonna close this connection
and we're gonna set self ID to be equal to the new poll ID
that we get from the database.
Of course we have to import database,
and we're also gonna have to
import this create connection function,
but we're gonna look at that in just a moment.
For now, just assume that it connects to psycopg2
and it gives us a connection back
and at the end we close it.
So we're gonna be using this function
in a few different places here
to create new connections as we need them.
Whenever working with polls, polls have options
so therefore it's possible to add options to a poll.
That is why we're gonna have a method called add option
that takes in an option text, which is a string.
And all this does is it creates
an option model class or object as in the option text,
and the poll ID, and also calls save on it.
The option model class is gonna be pretty similar
to the poll model class.
So, by calling .save in the option object
then that will save it to the database
in a similar way to what the poll does.
As well as adding options,
we also have to have a way of retrieving options.
So what we're gonna do here
is we're gonna define an options method here
that returns a list of option models
and this, again, is going to be the same class
as we're using there,
we haven't written it yet
but we're gonna write it in a moment.
This comes from the typing module,
so we're gonna do from typing, import list.
We'll also do from models, import option.
Which at the moment doesn't exist,
but it does get rid of these red underlines down there.
What this has to do is, again, create a connection
so we're gonna do connection equal create connection,
then grab the options from the database
so we'll do options equal database.get poll options,
passing the connection and passing self.id.
By the way, misspelt that.
Self.id is the ID of the poll
that we're currently working with
so, this will give us the poll options.
Notice that in this database call here,
we're just gonna get the options for a poll.
So we're not going to get the poll rows,
as well as the options rows, as we have now with a join,
we're just concerned here with the options themselves.
So that's something that we have to code as well.
Then we'll close the connection
and we are going to return the option object.
So we'll do option one, option two, option zero
for option in options.
The reason why we're passing these arguments
to the option constructor,
is because if you look at database.py,
go to the top here for create options,
an option has three values.
The ID, the option text, and the poll ID
those are gonna come back from our database.
So here we're gonna pass them into the option constructor
so that we can use those values from the database
to create new objects.
Next up, the three class methods that we're gonna need
to get a specific poll by ID,
we need that from app.py.
Here we are getting specific poll information
then we need one to get all the polls,
for example we need that when we are trying
to display the open polls.
And we need one to get the latest poll,
because we'll need that as well.
So, we're gonna go over to poll.py and create those.
If I leave them here,
all of these do the same thing essentially.
The get method takes in a poll ID
and goes into the database and finds it.
Notice that get poll doesn't exist yet
but we're gonna create it.
It essentially just retrieves a poll with that ID
and then uses the CLS parameter,
which is specific to class methods,
to call the poll class,
and it creates a new poll object
passing in this information from the database.
So the return type of this method is actually a poll object.
And because we can't do this,
we can't annotate a method of a class
with the same class that it returns
because by this point in time,
when this actually runs,
the class hasn't finished evaluating yet.
So this is actually invalid in Python,
we just put it as a string
and Python knows to evaluate this return type
after the class has finished processing.
So that is what this returns - a poll object.
The all method returns a list of polls
and once again goes in and does database.get polls,
which at the moment does exist.
It just selects all the polls.
And then what it does is it creates a poll object
for each poll returned by the database
and we end up with a list of poll objects.
Finally, the latest method does the same thing
but it just gets the latest poll.
And I forgot to pass in the connection there
so that's something that we need to pass in,
and then simply gets the CLS return type there
with the poll information.
We're gonna have to change something in here
afterwards anyway,
because this at the moment returns a poll with option list
and now we just want to get a single poll.
So we do have to make those changes,
but you can see that with the type hinting
Python actually tells us this is probably not
what we wanted to do with the current data types,
but we're gonna change them in a moment.
All right, so a lot of things new here.
But essentially what we've done is we've created
a class whose objects we can use
to interact with the system in a bit of an easier way.
Now we'll be able to, for example, create poll objects.
I'm gonna just put it up here as an example.
But we can say poll equal poll Flask versus Django,
the owner can be Jose,
and the ID let's say comes from the database and it's three,
we can do things like poll.add option to add a new option.
We can say Flask, and that is actually gonna go and save
the option to the database
without us having to do that ourselves.
We can print poll.options for example
and that is going to get us
all the options from the database.
And this is actually gonna be a list of option objects
that we can then further interact with.
Essentially, it allows us to be
a little more flexible with how we're
interacting with our system.
By the way, I might actually make this a property,
a decorator there, just so we can access poll.options
instead of poll.options with the brackets.
That's all that this allows.
If you're not familiar with the property decorator,
then I will leave a link
in the resources section of this lecture.
This is what I had in my notes,
but I forgot to add it in earlier.
All right, before moving on to adding the option class
we're gonna cut it here and do this in the next video
because this is getting a bit long.
So, thank you guys for watching this video.
I'll see you in the next one.