So currently, our API allows us to create posts and also list them out.
A really awesome part of Reddit, the sort of the magic, in my opinion, is when users can upvote these
posts so that they can see, you know, what are the most popular things on the Internet.
Right now, they call Reddit, sometimes the front page of the Internet because it's like these are
the things that, you know, most the users are interested in.
These are kind of cool things or important things of the day.
So we want to create upvotes or vote objects for our project if we come back to our code.
If we look at our models that pi a vote consists of a user and a post that that user wants to upvote.
So we're gonna do the similar thing for the vote here like we did in the post to say, you know, whoever's
making the call will that's going to be the user, the voter.
But then we do have to, you know, figure out what post it is that they're trying to make this vote
for.
And the whole reason we did this this way again was to make sure that someone doesn't vote for something
twice or else they could really game the system.
Right.
You have to have separate accounts voting for something in order for that number to go up.
So if we're going to have an API to create a vote, the first thing that we have to do is have a serializer
for that vote.
So let's go ahead and make a new serializer and I'm going to copy.
What we have here for the same line of class come down on a set of being a post serializer.
I'm going to call this a vote serializer to copy this meta stuff.
OK, bring that in instead of the model being a post.
It's going to be a vote object.
And instead of having all the fields that a post has, it's very different.
It could be tempting for you to say, oh, we have to bring in voter.
We have to bring in post.
But I do not want someone to be able to set those things.
And really, when we think about it, I don't want someone when they're setting, you know, hitting
up the API to say, you know, oh, this is the voter that I wanted to be in in the post.
That's going to be all contained inside of the you are real.
You'll see that in a second here.
So really, this is all that we need for the vote.
Serializer is just the I.D..
This is literally all we need.
OK.
So go ahead and hit save here.
Now let's move over to our your ls to say, OK, how is it that someone is going to vote for one of
these particular items?
So we're going to make a new path and a copy what we have here.
Loop's copy this paste down below and I'm going to say if someone wants to upvote something it should
be API slash post slash the idea of that post.
So let's maybe say one, for instance, slash and then we're gonna call it vote.
OK.
Now we can't just have the number one there.
That's sort of a place holder for me to say, you know, how do I want this to look?
Instead, what we're gonna do is we're gonna do angled brackets and then say we're looking for an ENT
colon and we're gonna call this piqué short for primary key.
All right.
Now, as for where this is going to go, it's not going to the post list, but we haven't made the proper
view yet.
So let's go back to our Vieuxtemps pie.
And instead of creating a list view, we want to create just a create.
So I'm gonna go ahead and copy a lot of what we have here.
Okay.
We don't need this comment there.
Let's get rid of that.
Okay, so let's make a new class instead of being post list.
I'm going to call this vote create.
All right.
And instead of being a list, create, because no one really wants to see individual votes.
Instead, let's just have this be a create API view.
So this is only going to be making new vote objects.
Now, we have to do a little bit of, you know, changing of things here for the query set.
It'd be really tempting to just say, oh, you know, go get all the different vote objects, but I'm
going to show you why this is not what we're looking for.
So we're gonna go ahead and get rid of this.
And instead we're going to say the serializer class instead of being post serializer, this is going
to be vote serializer, right?
The same one that we had created right here.
So we've got to import that.
We're gonna say we're looking for the vote serializer.
All right.
Now, as far as permissions go, we want to make sure that someone is authenticated.
Again, we don't want someone to be able to read this information.
So it's just going to say someone has to be authenticated in order to use this.
And then what we're gonna do this is what I was talking about before.
We do have to provide a query set, but we have to be very careful because if someone's trying to create
a vote, we have to make sure and see, you know, what particular vote that we're looking for.
We're looking for a particular user in a particular post.
So I'm going to do a function here called GET.
Underscore, query set.
OK.
And we're going to put self inside of there.
And we're going to say when someone is trying to get a particular object, we're gonna first grab the
user.
So the user is going to be equal to self.
Dot request dot user.
OK.
And we're going to say that the post the post that the user is looking for is equal to.
The post object.
Dot.
And let's make sure or not post.
We want to get you.
I'm getting confused between Votan post, but we are looking for a post.
Your story is a capital post, dot.
And then we want to do objects.
And then we want to go.
And this is where we have the parentheses, the primary key is going to be equal to whatever primary
key was passed inside of here.
So in order to get that information, we've got to say that this is equal to self.
Dot k, w, args, k.
That's how we access that piece of information.
And we have to pass inside of this dictionary that we're looking for the primary key.
OK, so we're still not done yet.
The whole point of this function is to return a query set.
So we are going to return a search for vote.
Dot objects, dot filter.
And we want to find votes where the voter is equal to the user that's currently making this request.
And where they post is equal to the post that we just pulled up here via the primary key.
OK.
So since we're using that vote object, we've got to make sure that we import it from our models.
OK.
So we'll go ahead and add that.
And now with this in place, we have the beginnings to be able to create something.
So let's go ahead and copy the name of this vote, create come back to our your LS and say, OK, if
someone goes to this, you are well, send them to the vote, create view.
So let's go ahead and copy the swing and a copy.
This Yoro that we have here.
And let's look at.
You know, let's go ahead and upvote the very first post that we have the one for zappy code.
So I'm going to go ahead and say if someone goes to slash API, slash posts, slash one.
OK, and wants to do a vote on this.
Are we not running the server here?
We've not set votes somewhere.
Let's see, Serializer, is that pie?
Guess we forgot to import that.
Yes, OK.
Copy.
Capital vote.
Save that.
Save our your URLs.
Looks like we haven't saved that either.
Let's reload this page.
And here we go.
All right.
So this is saying that someone here can create a post and notice it saying if because we visited this
page, it tried to do it, getting it, saying, hey, there's no get method allowed for this particular
your URL.
But if we try and go ahead and do a post here, it's going to have some issues.
Right.
Like, it has to be able to know what user it is that it's trying to save this for.
So this is going to be similar esq to what we did with the Post.
We're going have to do a perform create.
So go ahead and copy what we have here.
We're going to add this down to this class.
So perform, create.
But we've got to do a little bit more work here so that when we do the serializer not safe.
It's not the poster.
It's the voter that we're looking for.
But not only do we said that, but we also need to set what the post is.
So we're going to say post is equal to.
And this is where we want to grab exactly what we had listed up here, the post of objects.
I get all this good stuff, so I'm gonna go ahead and copy this, paste that there.
So now when someone saves this, the vote is going to properly go there.
So let's go ahead and save this.
Come back and let's reload this.
You RLC.
Let's do a post here.
So I'm going to do a post and look at this.
It creates a vote.
And if we go back to the admin portion of the Web site.
So this is just our Web site Slash Admon.
And we go to votes.
Look at this.
We have a vote object and says, look, it's AP code.
Voted for the first post.
But there's a problem here.
If we come back to our app and we wanted to do another post, look, it creates another vote object.
Right.
And if we, you know, reload the admin here and look at the votes now.
Well, now there's two votes for the very same thing.
So we could, you know, manually go in and check periodically if something's there and delete things.
But this is not a great method for us.
We want to make it and do a check and see.
Has someone, you know, already voted for a particular post.
So in order to do this, we're gonna come back to our code here before we do the create.
Before we do this Dotts Save, we should check and see if anything came back from this query that you
may be a might have been wondering why did we do all this work to go, you know, user and post and
do all of this here?
Cause, you know, currently the way things are, we could have abandoned all that.
But this is the reason if we say if self dot get.
Query set.
K Dot exists.
All right, with the parentheses here, this will check and see, hey, is there already a vote in the
database that has this particular user in this particular post?
And if there is, well, then we need to tell the user that, you know, this is not what they're looking
for and we need to raise an error to the user.
So in this case, we're going to say raise we're going to say capital validation, capital error.
And we're going to provide some text in here to sort of tell the user of this API what's going on.
So we're going to say something.
I think maybe like you have already voted for this post, maybe I'll even add a smiley.
So this is a friendly API.
So with this, we've got to make sure that we import the code for the validation error here.
So let's go ahead and go up to the top.
We're going to do from Rest. underscore framework DOT and then we want exceptions.
They import and we want that capital validation there.
All right.
So with this in place, I'm going to save come back to SSAFA here and I'm going to try and vote for,
again, the very first post as the zappy code user if I do this post.
OK.
We get an error here, OK?
I found the issue.
But if you want to sort of follow along how I found the issue, this might help you when you're debugging.
I always look for the name of a file that I have personally edited.
If I see anything that is, you know, for example, inside of the, you know, the Django framework
or the Python framework, I'm like, OK, I'm going to assume that code is OK.
But if, you know, there's something like my Vieuxtemps Pi, I probably had an issue here.
So if we go ahead and look at line 22 instead of reviews, Dot Pi, it's saying a vote has no attribute
object.
That is because it's supposed to be vote dot objects with an S.
Yeah, that's what I miss there.
OK, so if we go ahead and save that and now reload this page and I say, all right, I'm going to vote
for the very first post and I hit post.
Look what I get back.
You have already voted for this post and a cool little smiley face.
Isn't that awesome?
OK, so it knows that we haven't.
And I can keep hitting this button again and again and again.
But if I move back to the Admon here, you'll notice I still only have that one vote object.
Now, to really see if this code is working, we need to create a new user and see if that user is able
to make an upvote.
That is completely separate from the other object.
And in order to test this, we're going to talk about another cool feature of the rest framework.
Let's talk about that in the next lecture.