Welcome and Overview
Hello everybody and welcome to part two of the full stack web app in Python using Django and React. If you have made it here give yourself a pat on the back. Not many people make it past the first video so I hope you guys are going to stick around for the rest of them. But anyways let's get started. In this video we're going to be dealing with Django REST framework. We're going to be building some API endpoints. We're actually building our first database model.
What Is a Django Model?
All right so let's get started by creating our model and then we'll look at the API endpoint. All right so I'm here in my models.py file from my api folder. Let's just quickly discuss what a model actually is. So in a standard database you would have a table, you would have rows and columns in those tables and well that's how you would store information. Now that's no different in Django but when we actually go ahead and create a table what we're going to be doing is creating a model instead. So what Django allows us to do is write Python code and then it will interpret that Python code and automatically perform all of the database operations for us. So essentially it's just a layer of abstraction. It makes it a lot easier for us as Python developers to write database related stuff and well that's pretty much all there is to it. So we're going to go inside of our models here and the first model and actually the only model we're going to have for right now is a Room model. Now remember our app we want to group similar users together or group users together in a room. That room will have control over the host's music. Right like that's what we're doing for this app. We're having one person hosting or playing music and then other people join in on this room and while they can control that music. So first thing we need to do is make a class. I'm going to say class Room and inside of here we're going to inherit from models.model so this is just telling us hey this is going to be a model and notice that models is already imported at the top of our file. Now inside of here what we're going to do is define the fields that we want to have for our Room, so essentially the pieces of information we want to store for each room. Now I'm just going to tell you what these are but try to think to yourself what would we really need for a room? What is a room like? What comprises or makes up a room? Well the first thing we're going to have is a code. This is going to be a unique code that identifies the room. So we're going to say code equals models.charfield. CharacterField is saying okay and sorry this is models not model. This is going to hold a bunch of characters so our code is going to store a bunch of characters and well that's the way it works. Now inside of here we're going to say max_length. This is a required argument to the CharField and we're going to say what is the maximum length that this field can be. I'm going to say that it can be 8 and then we can set a default value if we wanted to. I'm going to set default, I'll actually change this something else later but for right now we'll leave it as blank. And then we can say unique equals true. What I'm typing here is pretty much the constraints on this field. So I'm saying okay what do I want this field to look like and what constraints or things do I want to make sure satisfied when I create a new code in my Room? Well first we want it to be unique, we want the maximum length to be eight and the default value will be, well something we'll put that in a second.
Room Fields: Host, Permissions, Votes, Created Time
Next each room is going to have a host. So a host is going to be equal to a models.CharField. The max length is actually going to be 50 and we're going to set unique equal to true as well. We're only going to have at most one host for one room so one host cannot have multiple rooms, that's a rule that we're going to set here. Now what is the host field? Well the host field is going to store some kind of information essentially that relates to our host or that links back to the host. I can't really discuss what that is right now because it's beyond the scope of what we're doing in this tutorial, but we just need to keep track of who the host is. Next we're going to have a field that says guest_can_pause. This essentially is the permission that says okay is the guest allowed to pause the music or play the music. This is going to be equal to models.BooleanField and we're just going to say null equals false which means we must pass a value and we'll say default equals false as well. Again if you want to look at any of these fields what you can do is just go look at the Django documentation. There's a bunch of different ones that you can use but I will show you kind of most of the main ones here. Next we're going to say votes_to_skip and that's going to be equal to models.IntegerField. Inside of the IntegerField I'm going to say null equals false and we can set a default value for this as well. I'm just going to set it to 2 but you can set it to whatever you want. Actually probably one makes more sense as our default. Then lastly I'm going to add a field called created_at and it's going to be equal to models.DateTimeField and this one has a really cool argument auto_now_add equals true. This means we never have to pass the date time to our object whenever we create a new Room it will automatically add the date and time that it was created at. So I know I went fast through this but these are the five attributes or kind of pieces of information for each Room and these are some of the constraints on those pieces of information. Again I found these fields just by going to the Django documentation and looking them up. Now of course you could add more if you wanted to. You also add methods on this model so we could say something like define is_host this right and then we take, you know, some host and then we check if that's that. We can add whatever we want and the basic rule in Django is that we want to have fat models and thin views. Now it's not going to be too relevant for us but that pretty much means put most of your logic on your model so that's what Django is trying to tell us to do.
Generating a Unique Room Code
Now I told you we were going to do something for code. So my code for the Room I want to be random and I want it to be unique so as every time we create a Room I want to come up with some random eight-digit code that represents that Room and that's what we'll use to figure out hey you know can we join this Room or how we identify the Room, right? That's what we're gonna do. So what I need to do is define a function here that can generate that code for me. So I'm going to call this generate_unique_code and inside of here we will say length and set this equal to whatever we want the length of the code to be. Now we can set it to 8 characters we can also set it to be something like 6. Let's just leave it at 6 and we'll leave the max length at 8 in case in the future maybe we run out of codes and we want to have more. Anyways we'll say length equals 6 and then I'm going to say while True and inside of here I'm going to try to generate a bunch of codes until I find one that's unique. So I'll show you how this works but this is cool because it's an opportunity for me to show you how we can actually query and look at all of the Rooms in our database. So first we're just going to go up top and I'm going to import string and I'm also going to import random. This is because we need to use this to actually generate the random code. Next I'm going to say code equals and then I'm going to do a blank string.join and inside of here I'm going to say random.choices plural and I'll go through this line after because it's a lot and I'm going to say string.ascii_uppercase that's going to give me all of the ASCII characters uppercase and the length what do I want that to be? Well I want that to be, so sorry k which is the length is going to be equal to length. Now I know this is confusing but this will generate a random code that is k-length so in this case 6 and that only contains the uppercase ASCII characters, that's what this will do. You don't really have to understand exactly why that works but we're just going to say code equals that and that will give us that code. Next we're going to make sure that this code actually is unique and the way we can do this is by looking at all of the Rooms in our database and checking if they have a code like this. So I'm going to say if Room.objects which technically gives me all of the Room objects and then.filter this is saying okay I want to filter all of these Room objects by what? Well I want to filter it by code and check if the code is equal to the code we have right here. Now I'm going to count this because what this will do is return to me a list of all of the objects that meet this criteria then I'm going to say if count is equal to zero then we're good we can break and we can return our code. So hopefully that makes sense that generates the random code and yeah I won't go too much more in depth in this function. I think you guys get that. Obviously if this is not true then we'll just keep generating more codes until, well, one is unique.
Migrations: Making and Applying
All right so that's good for models. Now what we need to do since we modified the database and we added a new model is we need to make migrations. So we're going to open up our terminal. Inside of here we're going to say python manage.py makemigrations and you can see we've made the migration. So migrations for api and you see what it says we created the Room model. Now that we made those migrations we need to apply them so we're gonna say python manage.py migrate. Now boom go ahead apply all migrations. Notice api is here. Apply the migrations and we are good to go. All right so now that we have this migration done we've created our model we want to set up an API view. This is different from a standard HTML view. I'll talk about the difference in a second that can return to us all of the Rooms that are currently in our database. The reason for this is we have to remember that right now what we're trying to do is we're trying to program a back end and what I mean by back end is just a server that essentially can handle information. So handle requests and then give some type of valid response. Now if we think about it it would make sense that our front end would want to be able to access or check specific Rooms, right? Say a user tries to join a Room, well it needs to look in the back end and say okay you know does that Room exist. So we need to create some kind of endpoint that can return to us information about the Rooms in a format that makes sense. We're probably not going to return HTML code. We probably want to return something say like JSON format where we have key value pairs that our front end can really easily handle, look at it and do things with. Now you'll see how that works as we go through but the first thing I need to do is create what's known as a serializer class.
Serializers: Turning Models into JSON
So I'm going to go ahead and make a new file called serializers.py and what a serializer does is it will take our model in this case a Room that has all of this Python related code so it has actually you know code equals this host equal this whatever it's in Python and it will translate this Room into a JSON response. You'll see how that works but essentially it will just take all of these keys here it will turn them into strings and then it will say you know colon and then whatever the actual value is that's stored here. It just does that for us. Anyways what we need to do inside of our serializers.py file is we're going to say from rest_framework import serializers and then we're going to make a class. We're going to say class RoomSerializer this is going to extend serializers.ModelSerializer and inside of here we're going to have a class we're going to say class Meta and I'm not going to really describe how this works but we need to define the model that we want to serialize and that we need to import so we're going to say from .models import Room and we're going to say model equals Room and then we're going to say fields equals and here we're going to list all of the fields that we want to include in the output or in the serialization. Now in this case I want all of them so I'm just going to say id and I'll talk about id in a sec, code, host, guest_can_pause and finally votes_to_skip. Now notice that these strings here match what I have in my model so code matches up with, let's get rid of test here, with code. Host matches up with host. guest_can_pause matches up with that, they're named the exact same thing. That's important. Now we also can return created_at, I don't want to forget that one, so we'll return created_at right there. But you're probably wondering why I have this id. Well on each of our models we have something called a primary key and the primary key is some unique integer typically that can identify the model in relation to all the other models so it's always unique usually an integer and it will be automatically created when we actually insert a new model or insert in this case I guess a new Room into our database. So even though I didn't define id here there's automatically an id field on every single model. So if we want to see that id field I can just put id here and it will return that information to us. Again this will all make more sense as we get through but let's go to our views.py now.
API Views with Django REST Framework Generics
We have our Room serializer. I'm going to get rid of this main function. What we're going to do is write what's known as an API view that will actually let us view a list of all of the different Rooms. So the first thing I'm going to do is return this or remove this http, sorry. We're going to say from rest_framework import generics. And what this will allow us to do is create a class that inherits from a generic API view. Again all gibberish until we start getting into it. So first I'm going to say class RoomView and then inside of here I'm going to inherit from the generics.CreateAPIView. Now what this will do is allow us not only to view all of the different Rooms but actually create a Room and all I have to give to this view is the following thing: a queryset which is going to be equal to Room.objects.all and a serializer_class which is going to be equal to you guessed it the serializer class we just made. So in here we're going to say from .serializers import RoomSerializer and that's going to be equal to RoomSerializer. Now I'm well aware and sorry we also need to import Room, we're gonna say from .models import Room. Now I'm well aware this all looks like gibberish but essentially what this is is a view that's already set up to return to us all of the different Rooms so that's what this will do if we simply tell it the queryset which essentially is what do we want to return? Well from here we want to return all of the Room objects that's what we're giving it and then we give it a serializer class that says okay these are the Rooms now how do I convert this into some format that I can actually return? Well we use the RoomSerializer which again inherits from serializers.ModelSerializer that just knows how to handle this kind of stuff. And now all we have to do that that we have this view is we have to link our URL to it so it's all going to come together. But let's go to our urls page here. Instead of importing main now let's import that class that we just made called RoomView. We can have both functions and classes being our views here. I'm going to say RoomView and now here I'm going to put RoomView but I'm going to add one thing .as_view. So this is just saying hey take this class and actually give me the view for it. That's what that is doing. So we're going to put that there. We're going to run our server and we're going to pray that everything works fine. Seems we get an error no module named api.models. Ah my bad guys let's go into serializers here and rename this models that's correct and see if that fixes it. Okay so that did fix it. Let's go to our browser now and we can see that we get nothing because we haven't gone to /api. So let's go to /api and again we still get nothing. Eh was there another path there let's have a look in our urls. Ah it's the home page my bad. Okay so /api/home and look what we get some fancy web page that tells us detail method get not allowed. Okay that's fine because this view is actually the wrong one, my apologies we'll fix in a second. But anyways you get the idea that simple little class we wrote. So if we have a look at it here in view actually allows us to have a view that well looks something like this. And notice that these fields right here code host guest_can_pause votes_to_skip are the ones that we had in our serializer class that were able to actually put information into. So what I'll do first just so that it makes sense when we go to the other type of view is I'll make a Room. So I'm going to say code let's just go like you know a b c d e f let's say host is just Tim like that guest_can_pause sure and votes_to_skip let's make that three. Let's post that request and oh there we go now have a look we get that information right here in this view. So it says okay you just created a Room it has id 1 this is the code this is the host guest_can_pause this is the votes_to_skip and this is when it was created_at. Okay so I accidentally refreshed the page and the thing went away but hopefully you get the idea that is how we create a Room and there you go you were able to see it before I know it went away because I refreshed but you were able to see that indeed that did work. And well there we go. All right so now that we have that let me just show you how we can change this view. So we created one Room and we'll change this to ListAPIView now and you'll notice that if I go back to this URL and I refresh it doesn't give me that post form anymore it just gives me a list of all of the different Rooms that are in my database. So this is extremely useful. We'll be using these kind of views for a majority of this tutorial and this is how we set up a REST API. We have a way to actually add information to the database which you just saw then we have a way to retrieve it. Now obviously I'm doing this using the user interface I'm using the browser but when we start setting up React we'll be doing this through requests so we'll just be sending say like a fetch request to an endpoint on the server and then that will return to us some information not in this nice fancy format with all this cool you know buttons and UI but it will give us just this raw data right here which we'll be able to process and then display on the screen. So hopefully that is all clear but that is what I wanted to show you in this tutorial how we set up a serializer how we set up a view how we get the models going all that kind of stuff that's what we need to do. So now we actually have an API endpoint at, where's my urls file here, /api/home and what that does is returns the RoomView.as_view and depending on what generic we use as the inheritance here we will get a different thing showing up. Now quickly I'm just going to change this to be room because I think it makes more sense that we have this be room rather than be home. But that's all I wanted to show you in this tutorial so if you guys enjoyed make sure to leave a like subscribe to the channel and in the next video we'll get into some more cool stuff.
Outro / Silence
[Music]