Build a Rest API with the Django REST Framework

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey hey what's going on everyone this is a rapid-fire tutorial I just finished it so I wanted to come back and make sure that you knew this starts may be a little bit slow but then it picks up very quickly so it's definitely not for beginners if you are a beginner literally just watch and you might have to watch it a couple times to really start to comprehend or even start coding it so with that said let's jump in welcome to the rest API basics tutorial this single video is essentially a introduction to our more comprehensive course but it's also an introduction to the Django rest framework if you're not that familiar with it and we're gonna be building a REST API so check out the description below or right here on REST API basics on our github page for the REST API project to just get more context and information about what we're doing essentially we're just gonna be building a REST API now the question you might have is why build a REST API in the first place now this has to do with connecting your Django project to any third party service or any client that you may build so if you want to build an Android app an iOS app or an angular app you want to have your own REST API and in this one we're gonna be skipping a lot of stuff and just jumping right in and building a REST API based off of a very simple Django project and that's what's in this readme here i'll actually show you some of the simple things that you'll need to add in to your Django project so of course I'm gonna assume that you have some Django knowledge and I'm also gonna assume that you're sticking with Django 1.11 if you use a different version of Django you probably will run into issues so stick with Django 1.11 because it's gonna be supported for at least the next three years okay so and also the other software requirements too okay so with that out of the way let's actually jump in to our project that we have already created now the first thing to note in our settings file we've got our installed apps here and we also have some rest framework related stuff again that's more or less copying pasting from that readme file the next thing is inside of my postings app I made a blog post model very very simple model you can just go ahead and pause the video now copy this I would say copy it exactly you could also use that github repository to copy it from there especially by the time you're watching this for those of you who haven't seen the on delete related stuff this is for future versions of Django so if you had to upgrade your project or something like that you're gonna want make sure that on delete is there what that means is simply when this instance is deleted everything related to it is deleted that's it okay or rather the user instance when that's deleted everything related to that user instance in this blog post is also deleted now I check out the docs for more on that okay so now that we've got this model and I've already have it in my admin and I also created you know a super user I ran my migrations I did all these things that you should have an idea of already how to do if you don't check out our try Django series okay so now that I've got this out of the way I want to start building my API so inside of my app postings I'm going to make a new folder in here and I'm going to call it API really this is a new Python module so that means I need to make an init file in here to turn it into a Python module now this API is for all of my API endpoints so what do I mean by API endpoints well let's go ahead and just make a little thing called notes MD and it's going to be number one a API endpoint and that is for crud so really crud related calls so create retrieve you know update and delete those are the things that I want to do with my API endpoint or in points right so that also means that I'm going to be able to have the list and search view right so in many cases as you may already know this can be combined into one and what we're actually going to do is say create list and search as one in point and then retrieve update and delete as another end point so as you also may be familiar these have corresponding HTTP methods okay so that's the other part of this is we have now HTTP methods let's just put this as another idea and it's going to be get post put patch delete those are the methods that were most concerned with okay and they correlate to these API endpoints and then finally we have data types and validation so the data type is going to be JSON validation will be a serializer and actually the data type is also serializer so essentially what we do is we create endpoints those are URIs is what they're called so you are I which is also often referred to as your URL but in this case these are resources we're trying to get some data that's kind of a resource right so we want to get these endpoints we want to develop these endpoints then we want to use these methods with our clients right so these are the client side it could be a it could be a back-end that's interacting with this but these are HTTP methods that we will work with and then finally the data that's being passed around is going to be JSON and then we're gonna use some sort of like middleman to make sure that the data that's coming through and going out is consistent and to make it consistent we use a serializer and then again it's using these same sort of endpoints so that's what we're going to be doing that's that's how we're building this now the reason I put an API module is to handle all of these endpoints were related specifically to our API versus our entire Django project now if you were just using Django as an API if you were building a REST API just for Django then sure maybe you would put it in the standard views file maybe you wouldn't it's it's really up to you I personally very much it's better to put its in its own module within the app then to do it anywhere else I think it just makes things nice and clean for us which we'll see as we start building it so how do we actually go about doing this now let's go ahead and create some of these API endpoints in the way of views so inside of this API module we're gonna go ahead and do views Dom pi here now just like the Django project we have generic views so generic views give us a bunch of convenient methods right they they're just very very convenient if I had known a spell convenient generic views just just shortcuts everything for us okay so what we need to do is import those generic views and of course with the documentation for the Django rest framework we can actually see all of the gent and generic views that are built in so in the API guy we go to generic views here we click on this and we can see all of the generic views right so we've got a create list retrieve destroy and update and generic views those are all those crud methods that we want as you also see is we have various ones that are just combined into one view if you remember back to our notes that we just created we wanted to put this as one and what do you know we've got one there it's retrieve update destroy and that is the API view that we actually want to go with we want to use that API view and if you want to get better understanding of where these things are coming from we just know that it's a generics so all the imports the examples at the very top of these Doc's so we can just come in to our views and do from rest underscore framework import generics and then we'll say class and this is going to be our blog post let's call it the rudd view you know missing the crud related stuff and of course it's just the retrieve update destroy API view so it's generics dot retrieve update Troi and that's what it is so with any detailed view so in in the Django generic views we've got a detailed view and what happens in that detail view number one we've got a lookup right so a lookup field of some kind so what field inside of our model are we looking up for a lot of times you use the PK which is aka the ID right so it's an integer right so that is a field that's built in by default to our models this should be well understood if you're watching this so that means that our lookup field by default is the actual primary key that is the default for the Django rest framework it has nothing to do with Django at this point that hat I mean of course it has a lot to do with Django but this setting itself is the Django rest framework so we can we can change that if we want it so in some cases you might have it as the slug or you might even have it as the ID now this makes a huge difference because when I bring this into my URLs which I'll do in a moment this is the actual regular expression that we're gonna have to use right so in our case we are gonna go ahead and just say PK and D plus something like this this is that regular expression and if you're using Django 2.0 this is where things could potentially break if you're not using URL regular expressions just to keep that in mind so we will actually come back to using that specifically but of course if I changed it to let's say ID I don't have to change that and change this just slight little things that we need to understand the next thing is we want to say our query set so the query set of course being related to our actual model so let's go ahead and import that and we'll do from posting stop models import blog post and the query set is blog post on objects not all and of course we can override this method by doing get query sent and we can return you know whatever we'd like here so if we actually needed to change whatever our query set was this is how we could do that we would do it in this get query set method of course since it's a retrieve you you bet we can also override the defiant get object method and we can return some sort of blog post instance right so what this lookup field default is doing is it is getting the primary key from self-taught keyword args get PK and then it would basically be doing get PK equals to pk that's essentially what it is doing as a default when we had that lookup field but if you declare this get object it's gonna override that and just completely ignore it which we don't want we're just gonna go off of the built-in methods here to actually make this stuff work okay so now we've kind of created one of the endpoints right so if we go back into our notes we've actually created an endpoint it's there and those methods are built-in which we'll see in a minute but something we haven't done is the data types and validations like we haven't actually built that into our endpoint now this is actually similar to how forms work so we're gonna go ahead and make a new file here call it serializers stop hi it'll do from arrest underscore framework import serializers and we're gonna go ahead and import from postings dot models we're going to import the blog post and we'll say class blog post serializer it takes in serializers dot model serializer whoo that looks a lot like forms dot model form doesn't it there's a reason for that let's make sure we've got our colon here and we'll do class meta name model equals to the blog post and the fields that we want to declare for the serializer I'm gonna put all the fields in so PK otherwise known as ID which you could put ID there and then I'll go ahead and say user and I'll say title and I believe the last one was content or actually the last one was timestamp so let's just double check those fields just go ahead and copy that if you need paste it we've got PK that hidden field user title content timestamp okay good so we now have a way to serialize this data again a serializer does two things it converts to JSON and also validates or validations for data passed this part of course we still have to see so now I've got this I'm going to go ahead and bring it into my view so from dot serializers this relative import we're gonna import the blogpost serializer and much like when we have a create view or form view inside of django we have to declare what the form class is we have to do the same thing for this because it's a update and destroy API view if is just retrieve we we well actually either way we would have to have this serializer class because that it does two things it again it converts it to JSON so it allows that that data to be in the right type but it also validates the data the data so the view is going to use it whether or not it's doing something like a form or create view does either way it's used okay so now that we've got this let's go ahead and create our own URLs file for this so URLs not pi let me go ahead and do from dot views import that post Rud view and i'm gonna go ahead and copy my urls from my main project just as a reference now again notice the URL patterns django 2.0 users this is not the same and we're gonna go ahead and put this in as a view here I'll just get rid of the admin related stuff and then of course it's not the home view it's now the post Rud view and I'll call this post - Rudd and I still actually want to import it so let's make sure I do that and let's get rid of these notes and there we go so we actually have our API URL set up at least for the detail view with the exception going back into our views we talked about this lookup portion so we definitely need to have that in here so I just add that in I'm just gonna paste it in here we just want and it's like this so we just want this regular expression right in front of that so we can see that in action okay so we now have our blog post Rud view this is a detailed view of course so finally what we have to do is add in this to our URLs so we have to make sure that we're importing the include method here and I'm going to go ahead and do URL our hat and it's gonna be API postings and then we're gonna leave it open-ended so we have those other URLs and we say include and this is postings dot API dat URLs and we're gonna add in the namespace of API - postings and put a comma at the end now that we've saved that again you want to make sure all your migrations are done and we're going to go into our admin here and I'm gonna create an actual blog post and I'll give it to my user and we'll say blah post doesn't really matter hit save and continue oh I got a Unicode error oops we want to go ahead and do the string of user username sorry about that little mistake I hit I hit that okay good now I've got an idea of one for this actual item we go into our API to like take a look at it postings one and what do you know there is our data it's in JSON and we can do several different methods on here so I'm gonna take a break for a moment I recommend that you do as well when we come back we're gonna kind of finish all this stuff off but as you see we've already done a lot of stuff and building an API in the last you know 17 minutes or so it definitely went really really fast I totally get that but the point is to show you how quickly you can get an API up and running and the reason I'm saying hey take a break go ahead and play around with this data now and some new blog posts do that sort of stuff just pause the video because that's what I'm gonna do I'm gonna pause the recording and then I'll come back and finish this stuff off so see you in a few moments hopefully you pause the video now so hopefully you paused and add some blog posts on there and possibly even played around with this console this is the API console that's built into the Django rest framework but as we've noticed we can see there's this delete option I can do put or patch here I could even use the HTML form that they have so there's a lot of different ways on how I can go about manipulating or working with this data before I move any further what I will say though is inside of my view if I change this to let's say for instance just our retrieve API view and saved that refresh in here all of those options go away and also if I changed it to let's say retrieve update API view only a few options come back as input or patch and we see that the HTTP methods that are allowed are there so again we're leaving that rudd sort of methods in there so we can do everything we need to do to this specific item now some things that are kind of cool about this if what if I change this PK to being like five and then I change the content saying changed PK and I hit put well I actually can't write the PK so so that's an example of a read-only field right so inside of my serializer I can actually set read-only fields so read-only fields and I can set them how I'd like so PK is one of them I could also set a user as a read-only field so if i refresh back in here obviously if I change this number to let's say two and hit put it doesn't do anything now if I didn't have that as a read-only field let's see what happens I do user two I hit put I say this user well PK invalid primary key so it's actually saying the user in Valon primary key of to object does not exist well what's that error that we see if we look on our user I only have to one user in here so that doesn't make any sense so read-only feels are really nice for when we're trying to manipulate the data but the nice thing about this too is that when I did try to change this user and had put of course it doesn't actually do anything right but if I wanted to validate the content further or any one of our fields I can do that inside of the serializer so much like we have in our forms we have a clean field name method we can do the same sort of idea but instead of clean its validate and the field name or validate the entire the entire thing but I'm just going to validate title and we'll say self and the actual value so the actual value is passed here so we can actually you know come in and make sure that this value is let's say for instance we want it to be unique so I would just basically say Q s equals two blog post on objects dot I or filter and we'll say title underscore underscore I exact equals to value and we'll just say if Q s that exists then we'll do raise serializers dot validation error and we're gonna say the title must be unique otherwise we'll just return back that value okay so we save that and now what I'm going to do is I'm actually gonna go in and try and make this value the same as a different post so let's go into my posts and just take a look i've got post two here so already this is the single one I'm going to call it post two I'll hit put and I'll say title must be unique I tried again it gives me that same title must be unique even with post so this is actually not the greatest because it's filtering based off of the actual object itself like it it's it's including the current instance so we actually need to exclude that current instance and to do that we'll just say if self-taught instance so if it even exists then we'll say q s equals to Q s dot exclude and P K equals to instant or self instance dot PK we say that we go back in here and hit put notice it doesn't give me that error now so if I had put a few times it doesn't and then if I change it to post to again the title must be unique so of course I would probably not say the title must be unique I'd probably say the title or this title has already been used all right very simple way of doing validation on this now of course this is just the one single model serializer so what I need to do now is actually create a view to create so we need the create view as well as the list view but first what I'm going to do is just to create view I'm gonna go ahead and copy this right here and I'll just call this the blog post API view and instead of all the retrieve update destroy I'm just gonna try create API view and I'll leave that gate query set in there and also the query set or the serialize or class that we have I'm gonna go ahead and import this into my views and then I'm gonna grab this right here and paste that in just like that and of course get rid of that primary key related stuff we don't need that and now I'm gonna call this post create and now let's go ahead and go to that endpoint I'm now where I can create it notice it says detail method get' is not allowed I can go to my HTML form I can actually create some data here notice the two things that are coming through user is not one of them right so user is a read-only field so let's go ahead and try and create one I'll say new item and I'll give it some random content and I'll hit post I get an error not null constraint the user is required so this is one of those things where it will require authentication now a very easy way to do this is say define perform create and it takes in self and réaliser like the actual serializer that's being passed and then we'll just go ahead and say serializer oops dot save user equals to self dot request die user will verify this stuff in just a moment but let's go ahead and go back in here and let's create our user or create our new contents our new content and I'll just say ABC I hit post now and what do you know new content is actually coming through so we now have a way to create retrieve update and delete we have all of crud one example that we don't have is the list API view so I'm actually they call this the list API view and will refresh back in here and now we've got our postings and we've got the four items that we have created right so our most recent one is here and then a few others we did off of the video so how do I actually combine that create method inside of here I did mention that we are gonna have it where it's those two things right so create search list and search so back into our view we have to use what's called a mixin you may already be familiar with mix-ins hopefully you are if you're not it's okay basically what I need to do is give this blog post API view the ability to create write so if I look at it right now the only ability it has is this get method so to add in the post method or any other method for that matter we can do posts requests args and keyword arts and then we want to return something here right so once I do that once I create that method and put it into any of our generic views I refresh in here it now allows that method really really cool that saves us a ton of time now that is doing the hard way that's the hard-coded way that's going to take a lot longer so we're not going to do it that way instead we're going to use mix-ins and going back into our documentation we see that make Sens are right here I click on make sense and we can actually import our mix-ins much like we did with our with our actual generic views so I'm going to go ahead and do mix-ins and the mixin I'm going to use is what make sense dot and we want to use the create model mix in right so make sense dot create model mix in okay so I did delete that post method but we actually need to bring it back in and say self request and then args and keyword args that post model mixin has the ability to handle that so we do self dot create takes in the request and the args and keyword ours so this method right here is handled by that create model mixin I'm just a quick primer on what's going on down here is you would do something very similar to post you would do put and patch and then we would say update update of course that is the different mixin so I'll let you play around with that if you are really curious about this if you want to see it in action check out that whole course but now that I've got that I can refresh in here and I see that I have these new methods and I scroll down more I see that I also still have those new methods but of course when we update things we want to we want to be able to actually look up that single item so we're gonna go ahead and remove those we definitely don't want them there but that's just generally how this works down here is it has those methods already written for it us and it already has a way to handle them so this right here is that built-in method to handle a create call so if i refresh in here and do some new awesome content and that's the title and say whatever for my content in it post what do you know it brings me to the actual created view it returns that response as its created it's a successful call and so on i refresh back on this page and now i've got 5 actual items so then i can go one step further and go into the actual URL where this thing is located really cool very very straightforward very easy the next thing i want to do is actually handle the search method now there's a lot of different ways on how we can go about doing this but i'm just going to show you the absolute simplest way which i think relates a lot of times to your other views like any general django view and that is getting the the query from the get method so if i do self dot request dot get get and i grab that cue item there this is where i'm actually doing the search so i'm going to go ahead and cut this out and say initially queue s equals to whatever that is and then i'll say if query is not none then we'll just query down that thing that query set itself we're gonna filter it down so filter and we'll just do title i contains equals to query and then we also might want to go even one step further which this of course is just doing more advanced query set related stuff so from django DB models we're gonna go ahead and import queue and I just put Q here and then I do basically aq lookup which gives me this or ability so it's going to look for this or it's gonna look for that so content or title and then I'll just do distinct to make sure that it's not any duplicates and then we finally return that query set that perform create method is still on there that actually has nothing to do with that that's more of the list API view so I refresh in here oops we have a spelling error so let's make sure that that's request I refresh in here cool so now I'm going to go ahead and do Q equals to some search I hit enter notice that it returns back a successful call but there's nothing related to that search because it is still a successful call it it didn't have any errors it just didn't find anything so in our case if I wanted to do you know post and just search for oh wait actually we don't need to put the parentheses in there we just search for post annual search finding for those things if I search for changed you know it finds that one so a very very basic search yes there are more advanced things you can definitely check out the documentation for the stuff that they have on there they also have stuff related to ordering really cool little neat features but the documentation makes it really easy to just try those things out yourself so going back into our notes we've now kind of completed this portion of things but one thing that we're kind of wondering is well permissions right how do we actually handle that well well we'll talk about that with the Django jot related stuff but by default what we actually put in here was this session authentication token right so something that you may or may not have seen is my user is actually authenticated and that's how I'm able to get these things going through now if I actually try to go back here it's going to give me this error authentication credentials were not provided so I wasn't actually logged in so this brings up the question is this the best method of how we're gonna leave things when I say that I mean should we go back into our default permission classes and leave it as is authenticated well no I can actually add or read only and once I do that I say refresh in here it doesn't change anything when I am a dedicated but when I go into an incognito window and I'm not authenticated now I actually get some data now see this is gonna be up to you on how you want that to work this is also true for any given item right so if I go here notice I have these allowed methods but I'm not authenticated so I only can see this one so if I tried to put or patch or delete it's gonna it's not going to let me do that right really really interesting as far as the permissions are concerned this is something that's important now what I will say though is when you go in your views you can change those permission classes right on here so permission classes and I can quite literally do whatever I'd like here as far as leaving it open this means that everything is permitted all permissions are there so if I opened this up into an incognito window again I now see that I can I mean even in the API console I can I can try to make something but of course if I try to make something hit post I get this error now that to do with this right so that is an error that is a problem that's something that you're not gonna want to have so let's go ahead and get rid of it and leave it as is okay cool so now we've got we've talked about permissions on the sense that you know if the users logged in they have permission the next thing is this blog post serializer right so update destroy API view this is where we might want to have our own custom permission so if I go into my API is here I'll do permissions stop I and I want to create my own custom permission so right off the vent I'm gonna be like okay I'm gonna go into the documentation and do it inside of the documentation I look for the permissions tab and I see there's custom permissions here and this gives me an example so if I scroll down I see two examples one of them is exactly the one that I want is owner or read-only so I'm gonna go ahead and copy this whole thing and paste it inside of my permissions part and I'll just go ahead and do from rest underscore framework import permissions now you may not know that by intuition so you would just kind of look and see where it's actually imported a very easy way to tell is this right here it says rest framework permissions and then when we went back in to that example it says permissions dot so hopefully that's fairly intuitive now what we see here is this call right here it saying instance must have owner an attribute named owner so there's a couple ways around this I can change this directly or I could actually go on my model instance itself and just add a property called owner and return self-taught user very simple you don't have to do that like if you weren't wanting to change anything about the model then you would just come in here and just call this obj user that's it but of course we don't need to do that I'm just gonna leave it with the example so this is 100% from the documentation itself and all of this is just saying hey is this like can we put the method or is the method that's request that are used in a safe method safe method being a get call right is it getting that data so that's the read-only portion of this and this right here is saying hey you know are we making sure that this is the owner of this object okay so now that I've got that I'm going to go ahead and import this into my view so from right above serializers I'll do from dot permissions import the is owner or read-only permission so now down here I'm going to say permission classes equals to that one now notice it's classes it's actually an array so you can have multiple permissions in there so we can save that and now refresh in here so this what this will do which we're actually not going to test right now but what this will do is if we're not authenticated obviously it doesn't it only gives us the read-only method but if we try to do it with a different user than the one that we're working with then yeah it's definitely not going to work for us okay so going back into our notes let's take a look at we've what we've done so far we've done this entire thing with the exception of the permissions call and actually getting the jot related stuff so we have an API endpoint we can create we can list we can search we can do retrieve update delete so we can do all of crud very cool very easy to do as you've seen I know that I'm flying by it but a lot of this stuff is just fairly intuitive and also not necessarily rest framework specific the rest framework specific stuff is also very intuitive because it's coming off of Django is very much based off of Django and the the intuitive nature of Django itself so I do actually want to create some new things in here and that is we want to actually run some tests so I will create a new file called tests PI and this specifically will be so we can test our API automatically yes there's other ways to test the API and you should probably implement those other ways but what we're going to do is literally test the API how we see fit and if you want a more in-depth look at how we do tests including you know having custom registration and custom authentication those sorts of things we do in that entire course that's a much more in-depth you know process so that's that's not that's out of the context of this video unless you guys are super super wanting it let us know in the comments otherwise let's let's keep going with these tests so first and foremost what I'm gonna import is the test case so we'll do from rest underscore framework dot test import API test case and we'll just go ahead and say class and this is going to be blog post test case or blog post API test case and it's going to take in that API test case so if you're not that familiar with writing unit tests like this it's it's fairly straightforward first of all you can have a setup method just like this and yes that is the syntax and they might have support for underscore it might be worth a shot on your in let us know in the comments if it's working for you but this is the default setup method so that means that we can create some things that are related to this test now a couple features about testing is it can be automated and it's a new kind of like different database so it's a blank DB so what that means is we have to actually set up some data in here to make it work so that data being we want to create a user object obviously and we probably want to create blog posts maybe maybe not now in our case I actually do want to create some blog posts in this set up process because of just the nature of how the setup like the actual testing portion works so what I'm going to do is literally create one user and create one blog post and then we will kind of add to these tests once we start doing the authentication related stuff so to create a user model we're gonna go ahead and do from Django contrib to off import get user model and we're gonna set user equals to get user model this of course is getting us that actually user models so I can do something like user dot objects that create and I'll say username equals to test CFE user and we'll give it a mail equaling to test at test.com of course those things don't actually matter because they will be deleted and you know something else that's kind of nice about this is I can get rid of objects and just say user dot set or rather set password and you know some Rando password that doesn't matter either and then just do user dot save so that creates our user now let's go ahead and create a blog post so from postings dot models import blog post and we'll go ahead and create this blog post related to this user so post on objects that create user equals through that user object so if that's confusing at all we'll just call this user obj go and then we'll say title equals new title and then we'll go ahead and do content equals to some random content okay so now what I want to do is let's go ahead and separate this out to make it a little bit more pythonic okay so now what I want to do is actually run a test so I'll do define test single user and we'll do self and we'll do Q s user two objects that count and this is actually user count and we just want to do self dot assert equal and this is going to be user count is one okay so we've created a very basic test and we can run it so inside of my project I'm just gonna go ahead and do Python manage top py and test and it's gonna give us one test and sure enough everything's good this is correct we could do that same thing test single post and just change the numbers around a bit and or the attributes around a little bit and do that same thing okay so our setup process is complete as far as this is concerned but there's a couple things I still need to do to actually test my endpoints one of them being is wrapping in or connecting with my URLs now you may be familiar with the get absolute URL method in regards to just standard django views you know you would reverse a URL or something like that to get that actual URL something i like to define is get API URL and this is the detail view for that single post in relation to the API so how do we actually get that well there's a couple ways on how you can do it you can actually go ahead and do from django urls import reverse and use reverse to get our URL now a quick reminder on reverse you get the namespace itself and you add that in there at a colon and then you get the URL name in our case it's post Rudd and you put that in there as well and then we add in keyword args equaling to a dictionary and whatever the URL keyword argument is in this case it's pk so we do PK and we set it equal to cell type PK this is kind of that method that you would use for the get absolute URL method assuming you were outside of the API and there's actually nothing wrong with using that method with the exception that we only get a relative URL so it's only going to give us something like API postings one it's going to be something like that but we want the fully qualified domain name in there otherwise we want the entire URI so the entire resource including the protocol like HTTP or HTTPS and also the domain name so to account for that we can use the rest frameworks for inch so from rest framework dot reverse import reverse and I'm going to call it as API underscore reverse because you might want to use both of these in this actual blog or and in this model itself so I just kind of changed the name of the function or the method to API reverse so down here I can use API reverse and if I really want it to use that get absolutely your all method I absolutely could one other thing I will mention is there's something called Django hosts that handles sub domain names so I would actually say if you have Django host use that one for reverse instead of the rest framework one because it will give you the actual URL that you desperately need okay so this API URL is useful in a lot of different places of course we're gonna use it on our tests but it's also useful in our serializer so we can use a field called URL and we're gonna use something called serializers dot serializer method field and this is a useful field for a few reasons but I'm gonna just go ahead and say read-only in here as to true and since I created a field here I'm gonna go ahead and add it in to my actual blog post or they serializer itself and now that I have this URL I can probably ignore the primary key it's kind of up to you on how you want to go about doing that but before I was figuring out what the URL was from the primary key but I want to be very explicit and give it in here now I say that it's actually the URI so that's the Uniform Resource indicator but we haven't really talked about that so let's let's just call it the URL so now we have this serializer method field which means that I now have to do something like get and then whatever that method field name was in my case it's URL so URL and it takes in self an object the actual instance itself so now we can return object get API URL whoa that was I mean hopefully all of that is just like proof easy no big deal got it if it's not hopefully you can go back in the steps and basically all I did was get this URL method right in this serializer so now when I look at that blog post and I take a look at in here I'm actually getting my API blog posts here so it's giving me the not fully qualified one so we might have to save our model again it's possible that I didn't save everything here so I refresh and wait a minute the URL is not correct now you might intuitively think hey it seems like it should work well it actually didn't so the reason for this has to do with the context so what on add in here is request equals to none and also pass that in as an argument because that is an actual argument that we can use in here and since I have this on this method what I need to do is get it on my serializer here so how do I actually get the request in here this is something that's fairly useful and what it can do is in my view I can actually add in the request to be sent to my actual serializer method and to do that we just go ahead and add in to find get serializer context takes in self args and keyword args and we're gonna go ahead and return a dictionary here of requests and all it takes in is self dot request the request is on the view itself so this out we can pass it since I'm doing it in the you know Rud view I'm going to also do it in the regular list view as well so that serializer definitely has it now so that means in here I can say request equals to self docket or rather self dot context get request and now I can pass in the request of being the request so since I've got this save everything and I refresh in here and what do I see now I have that fully qualified URL it has everything that I actually needed for that endpoint so since I've got this I probably don't need that primary care anymore like I said but you might you might still want to end up keeping it in there or you might want to call it a different name and you know you might want to I D instead of the primary key and just to be safe let's go ahead and make it a read-only field as well when I say safe you don't need to do it but it is something that you know you might want to get in the habit of thinking through what absolutely should be read-only okay cool so why don't we do all this a big part of the reason was to test it to make sure that it's actually working in a way that makes sense so what I want to do now is actually get any one of these objects like I want to do a test to be able to see how to actually you know get this data and I'm going to do it without the user being authenticated first so what I'm gonna do is define test get item takes itself and we want to get that created item that we did up here so how do we do this how are we actually going to get this item well first and foremost we might need data right so do we need data in a get call no we don't but I'm gonna put it in there because we might need it later and we do need a URL so what's the URL well we've already seen this actual URL stuff now I can get the fully qualified URL or I can get the exact same thing that I did before which was just the reverse version so I will actually bring in the rest framework URL call and I'll come in here and just do that exactly so what URL is for one single item what are we going to be getting well before I get any single item let's just go ahead and get do a test get list so it's just a little bit easier on us initially so I'm going to call the API reverse that we've seen already and well what's the URL name it is post create that's what we've been call it been calling it so I'll just actually change this to list create okay so we bring that back into our test that is the URL name and we called it API posting and that should give us our actual URL again checking API postings good thing I checked and this is API postings so that is what I need to test unauthenticated so what I'm going to do now is make sure that I can get this response so I'll just say response equals to self dot client this is built-in dot git and we're gonna go ahead and get that URL and we'll set the data and we'll also add a format as JSON like JSON format is the actual request itself and all we're gonna do here is do self dot assert equal and we want the response status code to be something that we may have already seen before and that should be fairly obvious that's this right here HTTP 200 okay now to do that we're gonna go ahead and import from rest framework import status and this is quite literally coming down here status dot HTTP underscore 200 okay now you can absolutely look this up in the documentation to see those things are right but that's what it is so I'm gonna go ahead and save it run the test again and oh I get an error right so it's giving me this error right here it's possible I didn't save everything so let's make sure I do save everything saved it again ran it again and what do you know we've got a get call being correct so that's awesome what about the actual data itself like we should check the data okay so let's go ahead and just print out the data first so I'll just go ahead and do print response dot data and see what that is and we've run that response data and here it is it's an ordered dictionary with well how many items or how many things is actually coming back it looks like it's a few things but it's not it's just one item so this is actually the same sort of content from that one single item that we created right here because of where that URL endpoint is so we just tested the get list item okay and what you will also note if we try to test the post or test post item like test a create item again we can put in some data here and say title equals to some Rando title and content being some more content this is roughly the same thing but instead of get we would use the post method now what is the status we should expect well I'm going to go ahead and delete that response data call and as well as there well let's just comment it out now when I run the tests again press up run the test and I get a failure notice this assertion error 401 does not equal to 200 so this is giving me a invalid request right because I used this post method so it's actually doing that test for us really cool so what that means is we want to actually say that hey this is an HTTP 401 unauthorized because that's what it is I run it now and now they are no longer authorized cool so taking this same idea a couple times I'm gonna go ahead and copy this and paste in here and this time the URL I'm gonna go ahead and say get item and I'm gonna go ahead and grab that first item for that blog post so coming down here we're gonna go ahead and do blog post objects not first and in this case this is again the get item I could just do blog post I get API URL alright so we created that instance method and this will give us that URL now and all of this related stuff should still be the same so again we can print out that response data and then test update item so now instead of post item but test update item we can still actually get that same stuff so coming in here in this case I'm just going to go ahead and change the data and that's it so it's changing the data from these things here okay so should we expect the same unauthorized yes but more importantly this method is also not allowed so what would this actually be would it be unauthorized or something different I believe it's going to be something different so I will actually do two tests on this one and that is the response being this post method being 403 and this is going to be forbidden and then we'll do put forbidden meaning the post call is not allowed on this endpoint so we've run it and I get two failures number one I get 405 so it's not a forbidden call so that is the error that it actually is so what's the 405 error going back into the documentation we look at status codes and we search for 405 method not allowed ah so it's not enough for bit in it is just simply method not allowed will I use forbidden well probably so I'm gonna go ahead and put method not allowed as the call I'll just paste it in for a moment because we might want to use this forbidden one later go ahead and comment that out so method not allowed is now in here so we're gonna go ahead and save it and run it again and what do I get no errors at all and I actually get that same data back that's coming through as expected so this data right here is coming back and it's coming back in a real way okay cool so we now have all of the tests done not related to an actual authenticated user right so all of this stuff handles that itself so now what we need to do is actually test the authenticated user which means that we have to have a way to get a token that will allow us to do said tests now luckily for us what we can do is we can test this without writing all of the URLs needed for user authentication so I'm gonna do that first I'm actually going to finish off these tests prior to creating an endpoint for these URLs so I'll go ahead and do from arrest underscore framework underscore JWT remember we added that in settings we're gonna import our API underscore settings dot JWT underscore payload underscore handler oh sorry we are just importing those settings but we want to say the JWT payload hand alert equals to this so I'm just going to call this JW t let's just call it pay load handler underscore just like that and then we'll say JW t or encode handler rather and that's going to be equal to the API settings dot and this is the JWT encode handler okay so what I what I'm gonna do here is I'm actually gonna get that information based off of our user so scrolling down to the bottom I'm going to go ahead and copy this one right here and we're gonna paste it in here I'm still gonna use that same blog post but now what I want to do is get the token that's actually coming from this user so the user itself is going to be that first user right like we created so I'll just go ahead and do user obj equals to user objects dot first okay so this is the user I'm using now what I want to do is actually say payload equals to the payload handler for that user and then we want to get the token and that's or the token response rather you know token response and that's going to be equal to the encode handler of that payload and then we want to do self dot client dot credentials and we're gonna do HTTP underscore all capitalized and that is equal to JWT and a space plus that token response so this is how you set a header for token so we're using the JWT token header and that is that rest framework token so every time I need to do a request that's related to my user I have to pass in that token so now what should happen is well we should still get the same error so I don't actually have to test for that anymore but what I should get with this response is something different so test update item with user we save that and let's go ahead and run it I get a failed error it says users not the fine oops I said user obj a little mistake there little save run it and we still get an error what's the error well this is now related to a status code so that's good what the status code is is this is should be HTTP and not you know the 401 unauthorized but now HTTP 200 okay so we actually did the update which we can see I can go ahead and do print let's say blog post dot content let's start off that way and then after this one I'm gonna go ahead and print out response dot data okay so we should see two different responses here I'm gonna take out any other print statements if I have them I do not save it and run it again and what do I see I see some random content and then a little bit further down I see some more content so I successfully updated that item based off of this user okay so I've actually tested that authentication stuff the one the last thing is you can 100% do this same stuff all over again for the create item this right here so let's just I mean really quickly do it it's not really that challenging here hopefully you know but I'm gonna go ahead and just copy these paste that in here and this will this should do it for me okay so now it should be a created call like it should actually allow me to create this item and that is going to be different than 401 now it's going to be created I save it and I've run it and well you know it's fine it actually does create it I'm gonna get rid of the print statements here so what I would encourage you now is test post item with user and call it that what I would encourage you to do now is to try these out with those different methods but of course there is still one last thing that I want to do is that is test user credentials or test user ownership this is more or less the last thing that I would want to do and that's this right here so what I need to do is create a new user and I'll just say username equals to test user 2 or whatever that's what I'm gonna leave it as and then I'm going to go ahead and create a new object with that test user so create a new object with that new user object and then we'll say that's the owner user so we'll just call this owner okay but that's still the object that I'm gonna try and update so all change this to being put and this should be actually the put/call little mistake as far as the data is concerned I'm gonna go ahead and copy these and bring it down here okay so we've got our token that we still want and that's going to be based off of that original user so user obj equals to user to objects dot first still that same user okay but now just a different blog post and we've got a URL we've got our title this user these related things I no longer need because I've set those credentials and then now I'm going to go ahead and try and put this data to this other blog post right so this is a different user creating a different blog post this is our first user our original user and we could also do self dot assert instead of assert equal assert not equal and that will be user obj dot username and owner dot username that's going to test whether or not they are not equal basically and this is going to create that payload for the other user and it's going to give us that authorization and then finally it's going to try and update it with some new content and I should get a forbidden call here so we save that and we run it what do you know we get successful call very cool and a lot of this stuff is just playing around with it learning more about tests in general but this is how you can actually run automated API tests and it's something that you really need to do because you can't actually test it in any other real way in a very good way at least this I thought was a pretty good way of actually going through and testing out this API itself but we are still not done so what I want to do is actually go to the jaunt documentation and I'm going to just give you a quick little rundown of what we just did that's already on that jot documentation and when I say is this import right here all of that is coming from their documentation so creating a new token manually that's this right here that's what I literally just did is create a manual new token so you can do this anywhere then and that means any custom API view or any custom view you have you can absolutely use that same method to actually send back a token with that user object anywhere it doesn't need the request at all it just needs the user object and it can actually create that token and then you just add that HTTP header for authorization so the authorization header you would add this in there itself so if you you were using something like Python requests you would do requests dot like post and the URL the data and then you would say like headers equals two and authorization and then you would put it jot plus whatever that token is right so that's essentially how you would do it and this is true on any sort of HTTP library doing the HTTP calls themself okay so that's that part but how do we actually get that token on our API anyway well we can go to usage and we see this right here so this is obtaining the jot API token so I'm gonna go ahead and grab this and we will come back into our project into our URLs our main project URLs and we're just gonna add this in here so I'm gonna cut and paste and do a lot of things kind of quickly and I'm going to go ahead and add a URL name to this and I'll call this API login because that's essentially what it is so instead of using their URL endpoint I'll just do API off and login put a dollar sign at the very into that and there's our new URL for API login how do we test this hopefully you have some idea we have API reverse here so I'm just going to go ahead and come down to the very bottom and do define test user login self and what's the data going to be well it's going to be the user name and the user name in this case is our t-test CFE user so we'll do that and then our password password and what's the password that we set in this test call some Rando password we set that in there and then the URL itself is API reversed and we called it API - login right so just the URL name because we don't have a namespace for it so back into that test and then we're gonna go ahead and go and do a post call so do self dot and this would be client post and it's gonna be URL and data and that of course is the response itself and we're gonna go ahead and print out the response data and then finally I'll go ahead and print out the status code being okay so I'll just assert that's equal just like that okay so testing user login let's try it out I'm gonna run it and I get a failed error hoops make sure to put a comma here run that again and what do you know it actually worked now why did this work why did this actually give me back a status code okay well it has everything all of these things have everything to do with this setup if you don't do this setup correctly you will fell things will fall apart now the big question to you should be should this test user login be on your tests for posts no it should be in a different place but I'm doing it so you guys can see it in action and actually be able to work with it now one other thing is I printed out that request data and here is a token so I see that I can do token equals two response that data duck get token it'll say if token is not none then well let's go ahead and verify this ownership actually sorry not verify the ownership but test the updating of this item like we did up here so I'm just going to go ahead and grab it and bring it back down here and this is where something like this would actually make sense so test user login and update which which again we didn't actually have to do this payload Handler and all this stuff any longer because we actually did the login in a different way right so I just wanted to show you those two different ways on how it can be done because it's still fairly important so that blog post I still need that one that's correct I've got data that's good I have a new user object which I no longer need I don't have to worry about the user object instead I have to worry about that token so I'm gonna just change this token RSP to just that token get rid of these things right here those three lines and now I should get exactly the same response so if the token is none then I'm just not even going to run a test there's there's probably something else that's going on here that would probably be caught in another test so for sure this token should come back again if the URL is incorrect then it won't come back and an air will be raised and you'll have to diagnose it so I press up I run it boom we've got it it's working everything's working as expected and as we so what's left what do you still need to do well what you need to do is actually create an endpoint for registration like we didn't actually do that all we did was create a REST API stuff so you can log in now in some cases you would have an API for registering in other cases you won't it's kind of up to you on how you're gonna actually handle the registration process so that's a really good challenge to leave you with now we absolutely do that in that REST API course on join CFE comm slash courses slash REST API we definitely do the registration there so you can see that but I definitely gave you enough here to be able to do the rest the register API call if you know enough about Django so if you know how to do a custom register API view in Django you can absolutely do it now now that you have a better understanding of building your own REST API so that's one challenge another challenge would be do this with more than one app and yes right these unit tests absolutely absolutely right these unit tests you can use this one as example if you need to now I see that mine has a lot of things going on with it but it's testing various aspects of the API to ensure that they're working correctly so before I ever go live or I ever even consider saying that that portion is done I'm gonna want to run this test to make sure and it's automatically gonna happen and of course if you haven't used unit tests before do note that every method that has test underscore whatever that will actually run the test it will if you have tests in the name of the function at the beginning just like this it will run a test the same is true for the actual module itself if it's called test stop PI or tests underscore or something else it will run those tests as well so yeah you want to make sure you followed these naming conventions and of course I wouldn't show you it the wrong way without explaining that I showed you it the wrong way now can these things be cleaned up probably you could probably write these two a little bit differently I wrote them in this way to test those various aspects that we already mentioned and now what you can also do as a third and final challenge is to actually build an API client probably using Python requests if you're not familiar with Python requests there's a lot of things that we do on it definitely our web scraping related stuff as well as 30 days of Python we cover that we also cover building that same client in that bigger course and if you've caught up with me this far you'll know that this is this is covering a lot of things we did it super fast but there's still so much more that we could have done to really clarify and understand these things on a much deeper level thus the reason for you to just join that other course but for those of you who aren't ready to do that yet this hopefully was a really good primer in the REST API related stuff now I will say I do have another video for creating a blog API it's called I believe it's called the blog API actually that one goes a little bit slower but it doesn't cover as much as this one does we actually you know refined that content over time based off of questions you've received that we've received and also the sheer demand for having a better way to test the API because this is the the right way to do it this is the the Django way this is the developer way is to write actual unit tests based off of it now something else that we didn't talk about were authentication classes right so in the settings itself we had these three different authentication classes and those were done by default so what I would actually do at the end of the day is probably only have the JSON web token authentication if all you're doing is a REST API if you have a normal jet and django web application with django views and all that then yeah sure you probably use the session authentication but that's something i also did not cover because well it's fairly straightforward on how it works the permissions is a little bit more important than exactly how the the authentication classes work obviously authentication is more important than permission but in the case of what we did here this is this is just a very good way of handling this and hopefully now you actually appreciate how thought-out the jus framework was I mean it looks so much like regular Jango views and Jango forms it just it's like just a joy to use once you start getting used to using it and you might have to watch this video a couple more times to really fully grasp all of it and yeah so that's it that's it for this one if you have questions comments concerns a concerns other than the fact that it was so fast I absolutely know is so fast I there's just so much to cover that I wasn't gonna make this a three plus our content video instead that's where that course is the course goes a little bit slower and it talks about these things in more depth but for many of you you might just want to watch this and not even code it but see how it's all done and then go and try and do it with the video that's just something that I've heard works really well and again also the other more particular reason as to why it was so fast is because this is not for beginners new beginners that are jumping into this I applaud you for getting this far if you did and if you followed along that's awesome I'm like really proud of you for doing that but it wasn't made for beginners it's made for you more advanced Django users that have probably mastered a lot of the things related to building a Django project without an API or a REST API so thanks so much for watching I'm super excited to do more rest API stuff so if you do have like suggestions for more REST API related things and just related to the API not any other third-party library like view or you know some sort of JavaScript client or whatever well let's not hear about those things just yet let's hear more about the REST API stuff and what you want to see done there even like if it's another authentication package for example so thanks for watching see you in the next one
Info
Channel: CodingEntrepreneurs
Views: 205,124
Rating: 4.9132214 out of 5
Keywords: djangourlshortcfe2017, django 1.11 tutorial, django tutorial, install django on mac, install django with pip, install django with virtualenv, virtualenv, python django, Django Web Framework (Software), Python (Software), web application development, learn django, installing django on mac, pip, python package, django, kickstarter funded, djangorestframework, django rest framework, rest api
Id: tG6O8YF91HE
Channel Id: undefined
Length: 78min 2sec (4682 seconds)
Published: Tue Dec 19 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.