Python Django Web Framework - Full Course for Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hey, and welcome to the try Django series.  My goal for this one is to help you learn   and master Django. Like I want you to go as far as  you possibly want to go in and understanding the   Django web framework you see in the way we're  going to do this in this one is really start   from the beginning, we're going to start with  absolute basics. And then we're going to work   our way up introducing new concepts along the  way. And I'm actually not going to be building   a full project. So instead, what I'm going  to do is just jump into individual concepts,   put them into a practical use case, in  a sort of project. And then eventually,   you'll have a very good understanding of how to  build real web applications using Django. Now,   of course, I do recommend that you learn from  entire projects and I have a bunch of them both   right here on YouTube on join CFE comm slash  YouTube, as well as on our website. Join CFE   comm we have a ton of stuff there for building  real things with Django. But this series is   all about getting the absolute basics to  even advanced level things, bit by bit.   If you're learning Django for the first  time, it's an incredibly exciting experience,   at least it was for me, because once I was able to  actually build a web application with, you know,   a database attached to it, it was like, Oh, this  is so cool. Now, I think that you might be just   as excited. And perhaps you've already done that  with other web applications. Or perhaps this is   the first time you're programming. Either way,  the most frustrating part is at the beginning,   not so much because of the programming language,  but often because of how to actually set up your   system. And since it's so frustrating, over years,  we were refined the way to set up your system,   depending on what you're on. And that's part  of the frustration is like, you're gonna see me   working a lot in a Mac. So Mac OS environment. And  if you're on Windows, you're like, hey, why isn't   it the same? I mean, actually using Python, and  actually using Django is the same on both systems.   Because Python is Python, and Django is Django.  The commands to get there might differ slightly,   but realistically, it's the same. Now over the  years, we've refined the installation process   and all of that can be found on join CFE comm  slash from zero. So if you just do that step one,   that setup process, you'll be ready for the rest  of this series. You don't have to go on to any   other step other than setting up your system.  Before you jump there. I did want to mention   one other thing, and that is the code. So we have  all of our code on GitHub or join CFE comm slash   GitHub to shortcut it, you're going to look for  the try Django repository. So So join CFE comm   slash GitHub will take you here. And then if  you go into repositories, you'll see all kinds   of them. In fact, if you type out, try Django,  you'll see multiple there as well. I want you to   ignore all of the ones that have numbers in them  and just go to the one, try Django, right. So this   is the link right here, if you want to go directly  there. But this code will 100% help you. Because   when you hit roadblocks, what you're gonna want  to do is take the code that you've been writing,   and take a look at GitHub, and make sure that what  you've been writing is the same as what we've been   doing in the videos. That part is critical.  And then the last thing is, when in doubt,   consult the documentation. Django documentation is  very well written. And there's just so much there   that you can learn that we won't necessarily  cover because they give additional context,   or they give specifics to whatever use case you  have for the technology. And then the last thing   is Google is your friend, you know, you can use  Google to do a search for something that you're   not familiar with. And oftentimes, that will  bring up stack overflow.com. Stack Overflow   has all of these questions from people for all  sorts of programming languages, including Python,   including Django, including JavaScript, all  sorts of things in there. And you just do a   quick search, you can search for just Django and  you can learn a lot just from that just from going   to like votes. I mean, does Django scale that's an  interesting question to take a look at. And then   what is normal, what is blank, I mean, this right  here is a great learning resource as well. So what   I'm going to assume for the next video and all the  other future videos, is that you have your system   set up and ready to work with Django and Python.  The versions that we're going to be using will   be discussed in the next one because they will  change over time. At the end of the day. I really   want you to stick with whatever version is in the  video because as a beginner, that is is critical.   Alright, so in this one, we're going to be  creating a brand new virtual environment,   and install Django. Now, if you haven't done  these things before, regardless of the version,   definitely stop now and make sure you go back  and do the setup process. Now, I absolutely   want you to have a fresh virtual environment and  a fresh Django install, not only just to get the   practice of it, but also to make sure that we're  all starting from the exact same spot. So if you   open up your terminal window, or if you're on  Windows, your PowerShell, or command prompt,   but hopefully you're using PowerShell, if  you're on Windows, Linux and Mac users, just   your terminal is fine. So if we type out Python V,  and Python three dash V, this is what I get. Now,   you might already have Python three in there.  So if you see Python 3.6, point five, or 3.6,   point six, right here, you're in good shape. If  you see this, then you're going to have to do   an extra step. Okay, just keep that in mind, I'm  gonna leave that open. And I'm just gonna put it   over to the side a little bit and break it down.  So we can just keep that in mind while we're doing   this. Okay, so I've got another terminal window  open. Now, you absolutely don't have to do this,   but I'm gonna leave it there just in case. So  there's a few different ways on how we can create   a virtual environment and install Django, I'm  going to show you the way that I'm going to do it.   So I'm initially going to show you the final way.  And if that part works for you, great, you can go   to the next portion, which would be installing  Django, which maybe we should just do all of   that. And so I'm going to show you exactly how I'm  gonna do it. Now I first of all want to keep this   virtual environment in one development area. So  for me, when I open it up, and I list everything   out, this is what I see, yours might be a little  different, yours might be the same, you might see   this dev folder, if you don't see it just do make  their Dev, right. So in my case, I already have it   there. So I get this error. I'm gonna just CD into  my dev folder, right, this is where I keep all of   my development projects. So in here, I'm going  to go ahead and make a directory called trying   Django. We're gonna CD into that directory. And  then we're going to create our virtual end. Now,   before it created, I'm just going to hit virtually  envy and make sure I don't see any errors,   I see that there's all sorts of options I can  do. If I type out ABC, there is an error. So if   you see an error, that means you need to install  your virtual environment all over again. Okay, so   I cleared everything out. But if I do pwd, I see  exactly where I am. I'm inside of that folder. If   I list everything out, there's nothing in there.  Now all I'm going to do is virtually envy dash p,   Python three, enter. Again, remember how I said if  you had Python dash V and Python three was here,   you can just omit this portion right here.  Right. So if you see Python 3.6, right there,   you can omit that portion and just leave  it as virtually ENB period, we had enter,   that creates a virtual environment inside of this  directory. So I can activate it with source bin   slash activate. And then I can install Django,  so pip install Django, and my version of Django   is going to be 2.0 point seven. So Django equals  equals 2.0. point seven. That should also be your   version of Django. If you're sticking with me on  this, use that version of Django, I honestly don't   care if 2.8 was 2.0. point eight is out, use 2.0.  point seven will upgrade things later. And if you   stick with me on this, you will absolutely upgrade  with us, I promise. Absolutely promise. Okay,   so I'm gonna hit Enter, and I'm gonna let  that run. Now for those of you on Windows,   your activate, you might remember is different,  just slightly different. While that installs,   I'm going to just go ahead and break it down a  little bit. I'm gonna open up another terminal   window, and simulate reactivating this virtual  environment. So I list everything out I CD into   Dev, and then I CD into try Django. I'm back into  that virtual environment. So I can do source bang,   slash activate and a Mac environment. In a Windows  environment. Of course, it's scripts to activate.   And then you can also run deactivate. Okay, so  deactivate just ends the virtual environment.   Cool. So what is the purpose of having a virtual  environment if you don't already know? Well,   it's as simple as doing PIP freeze. You see all  this stuff. I see Django one point 10.4. If I   activate it, source bend, I activate and do PIP  freeze. All I see is Django 2.0 point seven and P   ytc. That's it. So it keeps these requirements  separate. And when it comes to Python,   and it's projects like Django, you want to  absolutely make sure that that is done. Okay,   so we have everything installed. If this part was  done, you're ready to go, you can move on to the   next one, if you had some issues, or you want to  see other ways of starting a virtual environment,   stick with me. So notice that, obviously,  we had all this stuff installed, all that's   working. So going forward, just just watch just  for illustration purposes. You know, I'm assuming   that up to this point, if you have it working,  then you're done. If you don't have it working,   watch this next part, rewind, and then install  the things you need to install, because I'm gonna   go pretty fast, but still explain what's going on.  Okay, so I'm going to close out all of my terminal   windows and act like I'm starting from zero. Okay,  so I jump in to my terminal window I go into,   I'm gonna go ahead and make a new dev folder  called dev two, I'm gonna CD into dev two and   list everything out, nothing's in there. So I'm  gonna, I'm gonna show you three different ways in   creating a virtual environment. The first one is  just type out virtual E and V, and then the name   that you want to give it. So V and V, that is a  way to do it. Now this is your regardless of the   Python version, it's going to go off of whatever  the system's default version is. So I typed that   out. In my case, it's version 2.7. But that is a  way to start a virtual environment. Now, if I want   to start it based off of a specific version  of Python, I would do virtual env v, v, and   v, dash p, Python three, also, let's call this  V and V. Two. This gives me a version of Python.   And there's Python three. So that assumes that if  I type out Python three, it actually gives me a   Python three. But if you type out Python three,  and that doesn't work, this won't work. So what   happens then, well, I can just do which Python  three, or in other words, find the location where   Python three is installed. Right. So which Python  three will not work if Python three doesn't work,   right. So every once in a while you install Python  in your system, and it's just installed somewhere   else. And this command itself doesn't work. But  wherever that is actually installed on any system,   and you do something like this, you actually  paste in the path to that and hit enter,   that should actually open up Python three for you.  So then that means that the final way to actually   start a virtual environment is virtual MV, v,  and v three dash P, and then the path to that   Python three, I hit Enter. And then we'll actually  start that virtual environment as well. Now, one   of the thing I will mention is, we can also just  make the directory that we want to call it so I   want to make a virtual environment in a brand new  directory, this is it, I go ahead and hit enter,   I CD into it. And then I can do virtual ENB, and  then period instead of the name, and then whatever   version of Python I may want, right? So the order  of these things doesn't matter that much, how I'm   running those commands in comparison to what I was  doing before. But that's a few different ways on   how you can create a virtual environment. Now in  my case, I'm actually going to go ahead and get   rid of that dev two folder, I really don't need  it. But it was all about illustration purposes,   for getting all of this stuff going. Okay, so  I'll CD back into my original project. And just   go ahead and leave it at that. Now, if any of  this was confusing, and you're lost, rewatch the   video and do this multiple times, because having  a basic understanding of starting a new project,   installing it, you're going to probably do this  fairly often. If you're only here to learn some   of the basics of Django, and you don't plan on  making very many projects, which, with Django,   you maybe won't need to do it this way. Now, one  more note, I will say is, perhaps you're like a,   I don't care about a virtual environment. I don't  care about doing all these things. We'll do that   at your own risk, right. So you're gonna run into  issues if you don't use a virtual environment. And   yes, I am not using conda Anaconda is a package  that's more for like data science related things.   Django can use a lot of those same packages. In  my experience, Anaconda and Django don't work that   well. But realistically, if you're using Anaconda,  you're probably already familiar with that system,   and you're probably not going to use virtual  environments. However, I will say for this   entire series, I would recommend that you use  a virtual environment, just to get used to it   just to get used to how web developers often  use the development environment for Django.   Now it's time to create a Django project. See,  I've got my brand new clean terminal window open   because I want to get in the habit of knowing how  to reactivate a virtual environment. So I come in   here and I CD into my dev folder where I'm holding  everything I CD into my triangle folder, wherever   My virtual environment route is, and I just run  well, no, I don't run that virtual end command   anymore. We go ahead and run source bin slash  activate. Right. So that's Linux and Mac users,   for you Windows users, it's just scripts slash  activate. Okay. So if you are in here, you can   go ahead and do PIP freeze, and you'll likely see  this version of Django. That's the version we're   using, that's the version I recommend that you  use as well. So I'm going to just leave that open   right over here, so we can always see it. Right,  just a nice little reminder. Hey, that's the   version of Django I'm going to be using. Alright,  now, let's go ahead and do that all over again.   It's really easy, right? This this, hopefully,  this is really, really easy. If it's not really   easy. I'm going to fast, maybe just put it on a  slower speed. I know I talk really fast, but I   try to get it so beginners can keep up. But also  advanced users, like more advanced web developers   that are just learning Django, so all of you can  get something out of this. That's really the goal.   It's, it's it's a little bit ambitious to achieve.  But anyways, okay, so now we're in this virtual   environment, and I have this command Django dash  admin. So Django dash admin is a command that will   allow us to do all sorts of things with Django,  but the main one is creating our Django project.   So Django dash admin, create, project, and  whatever our projects name is going to be. Now,   you can do this right off the bat inside of that  virtual environment. But what I like to do is   create an src folder, as in the source folder of  the project, and then I go in there, right? So if   I go back into my virtual environment, I see that  we have these things in here, right? So I've got   the four, the four things related to the virtual  environment. And then I have my src folder. So I   change into that src folder and just do Django  dash admin start project. And then my project   name, what am I going to call it? Well, to be  original, I'm going to call it try Django. That's   the name of my virtual environment as well, I  realized that, but that's okay. You can name   your virtual environment and your Django project  the same, because the virtual environment is   only for your system, the project itself will be  other places, right. So like, you'll be on GitHub,   and there won't be anything related to our virtual  environment. So I'm gonna start this project,   try Django. And I'll just put a period at  the end, because I am in that src folder,   I hit Enter, and I list things out, I see managed  our PI, and my try Django configuration folder   that has the name of, you know, try Django because  that's the name of the Django configuration. And   if I run Python manage.py start or excuse me run  server, what I should see is it's saying something   like this, yes, it's giving me some warnings,  we don't have to worry about that yet. But it   is giving me a web address that I can go to.  So if I open up my web browser, and go there,   hey, congratulations, you have Django working.  Now, if you're not familiar with Django 2.0,   and this is new to you. This is a new landing  page that they've created, it looks a lot cleaner,   I like it much better than the old one. For sure.  So So we now have Django working, it's ready to   go. So there's all sorts of things that we can do  with it. But before I actually jump in to Django   itself, what I want to do is start working with  some sort of text editor, somewhere that I can   write the code that is not necessarily inside of  the terminal, because that gets super tedious.   For especially for beginners, it gets very, very  tedious to write code inside of the terminal. So   we're going to do something different. And the  next one will talk about that. So stay with us.   In this one, we're going to download a code  text editor. So writing our code is just a lot   more user friendly, than just typing all of the  commands into the terminal or PowerShell. Right.   So we're going to be using Sublime Text. But  another one a another popular one is called pi   charm, or p y charm. So Sublime Text is 100% free  to download and use. If you really like it, you   can just go ahead and buy it. I am not affiliated  to either one of these, I just know that they're   both very popular choices to write out your  code. And if that's all you're really doing   here is you're just writing out your code in these  things. They do have some features to make them   even more user friendly, but I'm not really going  to go into that right now. All I'm going to say is   just go ahead and download this and get it up and  running. Once you do just open it up and you'll   see something like this, right. So you can have  your window open, make make your sidebar open,   and you'll see some blank page just like this. So  all we really need to do is add our project into   it. So to do that, you just go into project, add  folder to project. And then we want to navigate   to wherever our project is. Now in my case, I go  to the hard drive users, my user, the dev folder,   because that's where the terminal opens by  default is right in here. And then try Django,   I'm going to go ahead and hit open. This brings  in all sorts of things in here, right, it brings   in virtual environment related stuff. And it also  brings in my src folder, which has my manage.py,   and all sorts of Django related things, right? So  So this is one of those advantages of using a text   editor is it just makes it really clean and easy  to see what's going on with any given code. And   it also gives you these numbers or these lines of  code, right? So I can say, hey, look at line 10.   And you already can go boom, line 10. Okay, cool.  So that's another aspect of using a code editor. I   mean, there's so many things to it, that I'm just  not going to go into now. Because I could, I could   spend probably an hour just going over the setup  process of Sublime Text, maybe not that long. But   anyway, so we now have this folder in here. And  we're pretty much ready to use this project. But   what I want to do is just save the project inside  of sublime text in here and just save it as try   Django. This workspace thing that's an extra  piece on our testing, so don't worry about that.   I save it in here, I've got my sublime project.  Now, of course, if you close out Sublime Text,   and you are in your project itself, and you  have something like this, like your, hey, I'm   navigating through back to where it was, you know,  you can just double click on this. And hopefully,   it'll open up sublime. If it doesn't, then just,  you know, do the thing that you need to do,   which is get info. And just say make sure that you  have open with, you know, Sublime Text on there.   If you're on Windows, it's right click and, you  know, doing the same sort of thing where you just   want to make sure that it opens up. But the nice  thing is, then it just cuts to right where all of   my code is. And I can open up all the different  files that I need, and make edits and changes to   them. Sublime Text is really cool. I really like  them. I wish they would sponsor these videos,   they don't. But I really liked their product. So  go check it out. and download it because we're   going to be using it a lot. It's not required,  but it is highly recommended. See in the next one.   Let's talk about settings.py. This is absolutely  a basic thing that you'll end up using a lot. It   has a lot of implications for your project  altogether. So we'll just go sort of line by   line as to what's going on here. Of course, you  can read more on the docs, because there is more   that is going on behind the scenes. And just  what we'll mention. First and foremost, we of   course import the OS, because Django works on any  given operating system, Windows, Mac, and Linux,   all of you guys see the exact same thing if you've  done what we've done to this point. So you see,   we import OS, and then we have this variable  named base dir, that's set to this long string   of what the heck is going on. All this does is  gives us the path of were managed up high is   but more specifically the folder that is holding  managed up py, which in our case is src. So it's   that folder right there. Okay, so how I know this  is, well, I know Python, well, I know Django well,   but how you can figure out where that directory  is. That's this right here. So based or just   gives you in my case that right? So your user  might be different. And if you're on Windows,   it's going to be different for sure that the  slashes will be in a different direction. So the   nice thing here is we know that Django knows where  it is in the system. That's that's important,   right? So we can do things relative to Django,  inside the entire project. That's pretty cool. And   is based or shows us that right off the beginning.  And you know, you can print out what the bass stir   is, too, if you were so inclined. You can print  that out and just run the server again, let's go   ahead and run that server again. And what do you  know, it actually prints out that directory for   us? Right, just like I said, that's where it is.  That's what it is. Cool. Next thing is the secret   key. Every Django project has a secret key that's  associated to it. They're always unique to that   project. Or at least they should be unique to that  project. And you don't want to make it you know,   public in production because it it could possibly  lead to security leaks, and you don't want that.   So just doing a couple changes. is good. Okay,  next thing is debug. This is something that's   very useful while you're learning or while you're  developing both things. When you bring it into a   live server or a live production environment, it's  a real website with real people, real strangers   using it, you turn that to false. And then has  some implications later, allowed hosts like domain   names that are allowed, not going to get into that  right now, installed apps. This is a cornerstone   of Jango. installed apps, there's a bunch of them  installed by default, which we'll go over later.   But this is where you're going to build your apps.  Like, you know, if you have a blog that you're   creating, you would put it in an installed apps,  if you have products, a list of products that you   have, you would put in installed apps. That is, I  mean, very core to Django. And think of apps more   in terms of components than apps, right. So like  apps has taken on a new meaning. Like your mobile   phone has a bunch of apps, it's not like that.  It's more of like little pieces of the greater   Django project itself, middleware. This is the I  mean, there's a lot of things going on here. But   it has to do with your requests and how requests  are handled, and also how security's handled and   stuff like that. This is something we'll go over  later. It's definitely more of an advanced topic.   But it's nice, because it allows us to know that  there's a lot of security features built in,   as we can see with some of the ones that are  already there. Root URL comp, this is something   we'll definitely cover for sure, too. This is how  Django knows how to route any given URL, you know,   so like, I'm my server is running right now. So  if I take a look at that running server, if I   go to slash, you know, it, whatever this is URLs,  like so those things are automatically routed by   default by Django, something that's really cool  as a built in feature in there. The next thing   is templates. You know, like Django renders out  HTML templates, we're going to go over this a lot.   But basically, like, where do we store them? And  how are they rendered? How do they work, all that   stuff will go over later. But it's essentially  the HTML page then gets rendered in Django,   it's really cool. It's very useful. And it's  definitely a common topic that we'll go over. The   next thing is the Ws gi application. This is how  your server works. So the server goes through and   uses this setting that's here. In some cases, you  change it. In other cases, you just leave it as   is. Next thing databases, Django maps to databases  really, really well. So MySQL, Postgres SQL, and   a few others as well, very easily maps to it,  you just change your back end here, where it's   located. And some of the other settings, you can  go in the docs to see all of that. But by default,   it has a sequel lite three database already there,  as you might see, right there. That's pretty cool.   Next thing is we have password validators,  this just validates that passwords are good,   or at least good to the current standards of what  Django is found. We have some internationalization   stuff. I'm gonna skip that for now. And then  finally, static files, like where do you store   your images, your JavaScript, and your CSS? Like,  where do you store those things? static files is   something we'll absolutely talk about as well.  But But settings is kind of controlling all this,   right. So it's pretty fundamental to how all of  our Django project is running. And that's in our   main configuration. I mean, that's it. That's it  for settings. I mean, we will talk and use these   things a lot more. But what I did want to mention  is one last thing, one actual practical thing is,   is that that database thing, so we have this  error here, and to run our database, we can run   Python manage.py migrate. So what this does is it  actually syncs our settings, whatever settings we   have, with our Django project, and in whatever  apps we have, we're going to go over this again,   for sure. But all this is, is this right here. So  we've got dB, that SQL lite three, I just said,   Hey, database, make sure you in Django are  hooked up and you're ready to start working.   So if I actually change this DB to I could  run migrate again. And what do you know,   Django actually creates a brand new database for  me. Now, this is pretty much only true with SQL   Lite. If you had MySQL or Postgres SQL, you'd have  to create those databases themselves. But for us,   we can just do whatever you'd like. As far as  the database is concerned, I'm gonna go with   the default, db does SQL lite three, I'm gonna go  ahead and delete that file. Now we have a better   understanding of how settings work. Let's go ahead  and create our first app. See in the next one.   Now it's time to talk about one of the key  components of Django and that is apps. You   should think of apps as components or pieces  of the bigger Django project. Right. So they're   the little bits and pieces that can hold a good  amount of code. But they're not like apps like on   your mobile phone. Right? So if you jump in to the  code itself, we see that we already have some apps   installed by default. Right? So this is also where  you'd put third party apps, as well as your own.   Right. This is pretty cool. So let's take a look  at the default or built in ones that we can look   at. The very first one is called admin. And if I  go into my project and type out admin, I'll see   something like this, this Django administration,  right. So I already have a username and password   filled in, because I use Django all the time.  But you probably won't see anything in here   yet. You know, and actually, the question should  be is like, how do I actually get in here? Well,   I'm going to go ahead and jump into my terminal,  notice that I have two terminals, windows open,   I have one that's running the server, and then  one that's just in the root of the Django project,   also known as port managed py is, you can  see how I got there, right there. So there's   a couple things that definitely need to happen.  First of all, I want to make sure that I when I   run Python manage.py migrate, I see something  like this, right, I have a few apps on there   that are built in those are there by default.  I don't want to see errors here of visually,   but you definitely want to make sure that migrate  is done. Because we want to create our first user   and then is Python managed up UI create super  user, that one command will allow us to create   a user that has access to the admin. This is not  a regular user, this is just the ultimate super   user, right, so the user that you'll end up using,  in my case, I'm going to use the username of CFE,   I'm going to leave a the email address empty,  and then I'm going to type my password. Now,   the password typing doesn't actually show up. And  also, when you're developing when you're testing   and you're learning, you can use whatever password  you want here, it doesn't have to be that secure.   It has to be secure. When you go live, when you  build a real project, that's when you really   want to be secure. So I've got my username here,  and my password in my case is just learn code,   all lowercase. And I can actually log in to  this admin. Okay, so what I did here was I   actually create a user that's actually in the  database. Django did all that stuff for me,   I didn't have to do anything. Really cool. So that  makes things super easy, super user friendly. And   that same action would happen, regardless of the  database. Pretty cool. So we actually just talked   about the first portion, or first two portions of  built in components, or built in installed apps,   right? That's off an admin off is that user,  right? So I actually created that user,   I created a super user. And then admin is what  I just logged into, right? So I can click on   users. And I can see more about this auth user, I  can come in here and say, Justin Mitchell, right,   and hello at team CFE Comm. And what do you know,  that is my user? Now, I can save it, I can do all   sorts of things in here inside of the admin.  We'll talk more about the admin in the future.   But it's really cool. I can also delete users,  I can go back and create new ones. You know,   there's a lot of built in things about the admin  that are really nice. But this is all about the   apps, right? The next few things, well, they're  not relevant to us just yet. So what we want to   talk about is actually creating our own custom  apps. So we've done some of the basics. Now let's   do a custom app of our own and have it inside  of the admin. When I say custom app, I mean,   our own data. So our own structure of data.  Let's see what that looks like in the next one.   Now, last one, we saw some of the built in  features of jingoes. Project, right, we saw   some of these components, also known as apps, that  allowed us to have a user and an admin. Those two   things are phenomenal. They're really easy to use,  and very user friendly. But what we want to do,   and the purpose of using Django is to build  our own apps, our own components. Now, let's   not confuse apps with like, what's on your mobile  phone, it's much more about just little pieces of   this greater hole. That is your web application.  So let's go ahead and jump in to the root of your   Django project, I'm going to use that term a lot.  The root of the Django project is referring to   manage py, so where manage.py is assuming that you  have your virtual environment activated, that's   where you want to be whenever I say root of the  Django project, I'm going to assume that that's   the case. So I'm navigated there. And of course,  this is where it's actually located on my system.   Might be a little different for you. If you don't  want to get there, just go back a few videos in   this series, it's linked below, make sure that  you watch some of the basic stuff there. Anyways,   let's go ahead and create our own custom app. So  I'm going to do Python managed up UI, start app,   and then whatever we want to name the app. Now,  I'm gonna go ahead and name it products. And you   can do the same thing by pressing up and renaming  it to blog. Or you could do it to profiles. Or   you could do it to cart, right, so I can name  it all sorts of things, right. And honestly,   those four names actually fit with like an e  commerce project, right. And if we look back   into the code itself, you see that, hey, I've now  have all of this new code inside of the name of   those different apps that I just created. Now,  this does show us something that we could work   towards, like, we could totally build an entire  project that does all of these things. But also,   what it should illustrate to you is that each one  of these apps should do one thing. And one thing   really well, like, the products app should really  just do product related things, not cart related   things that should be separate, that should be  in its own cart app. And we'll get to what that   means later. But the idea here is that your app  should be pretty narrow in focus. Once it starts   to get wide, that's when you start to bring it  into another app. And as you see, it's really,   really easy to create an app. So there's really no  reason to not do it, other than perhaps laziness.   And I want to avoid that in the long run for you.  That's why I'm telling you about it now. Okay,   so I want to show you how to use an app in the way  of storing data. Okay, the apps are really good   for storing data and mapping what data you want to  store to your database. So that means I'm going to   go ahead and delete some of these other apps that  I just created. Because we just simply don't need   them. Because we're still learning, right? So I  deleted it deleted these other ones, and now I   only have products. So opening up models.pi. We'll  talk about the other files later. But for now,   just models.pi I want to store a product, right?  So I want my back end to have memory of a product   that I created. How do I do that? Well, I write  a class called product. And in this class,   I wanted to have various attributes to it.  Right? So I want to say that it has a title,   I want to say that it has a description.  And, you know, perhaps that's it for now,   maybe I just want title and description. Maybe  I want price to Okay, so let's say title,   description, and price. Now I want these mapped to  the database. So how do I actually do that? Well,   in Django, it's actually fairly straightforward.  And we use something called model fields. So   models.we, just type out models dot, it's already  imported by default. And I'm going to just use   a text field for each one of these for now.  We'll talk about more advanced fields later,   but let's just use text field on each one.  Okay, and then my product itself, the actual   class that I'm using here, I needed to inherit  from the default Django class of model. Okay,   so this means that it's going to get a lot of  features that we absolutely need to make this   work that we just won't go into just yet, that's  getting more advanced. But here is a very, very   simple model called product. This will map to the  database. And we'll see that in just a moment. So   since I created models.pi, and I created this app,  I need to add the app in the settings installed   apps. And that's really simple. I just put my own  here and just write out products, the name of the   app that I created, right, so that's the folder  here. So I've got products, I have installed apps,   I'm just going to go ahead and put a comma after  it. And now what do I do? I, of course, make sure   that I save my settings.py and models.py. And  now what I can run is this thing called make   migration. So Python managed.py, make migrations  and then Python managed.py migrate. Okay,   so those commands, you're definitely going to want  to remember so Python managed.py, make migrations,   and then Python managed up, py migrate. Okay, so  the first time I did it, it made some changes.   The second time I did it, it didn't do anything,  right. So I want to run these in conjunction with   each other every single time I changed models pot.  So let's go ahead and add in another field here,   and I'm going to just going to say active. Okay,  or let's just do summary and Set a description,   right? So we got description and summary, those  two might go hand in hand. But now I've made a   change to the model, I saved it. And now I want to  run, make migrations, again, it's gonna ask me for   basically a default. And I'm just gonna go ahead  and say two for now. We'll get into that later.   But I'm gonna go ahead and say default and say,  This is cool. exclamation mark. Okay, so I run,   make migrations again. And then I run, migrate  again. Now, why the heck did I show you all   that? Well, the main reason is to remember that we  always run, make migrations, and migrate when we   make changes to models of Hi, anytime, anyplace,  anywhere, that is super, super important. Cool.   So we've got this model now. And I want to take  a look at this model inside of the admin. So all   I do here is go into admin.py. And do from dot  models import product. So this is a what's called   a relative import. It's importing the product  class from the models.py. And it's relative,   because admin.py and models.py are on the same,  you know directory, they're in the same module. So   I can actually do that relative import. And all I  do here is admin dot site, register, and product.   We save that. And with our server still running,  I go back into my project, my Django admin,   I now see this new thing here called products.  And I can add new product, new description, some   price. And the summary, hey, I've got my default,  and they're saying, This is cool. This is awesome.   Hit exclamation mark had save. And there we go,  we've now created a new product, and it's saved   in the database. And that's the that's really the  core and the basics of it all, right there a basic   model saved in the database. Now I could use this  over and over again, to save all kinds of data in   the database. This is not a great model, I will  say that like this is pretty limited in scope on   how it is, we'll get into more advanced features  of that later. But for now, that's pretty cool.   That's all we have to do for a model. That's  it. So what we still need to do is see how to   do this in the Python shell, that is actually  just using Python commands to save some stuff.   And now what we want to do is just use the Python  shell to create new products. So I use the admin   before, now we want to use the Python shell. So to  do this, I want to make sure that I'm in the root   of my Django project, you know where managed.py  is. And I'm gonna run Python managed up, py   shell. So when you do manage.py shell, that means  that all of the Django project stuff will work   inside of a Python interpreter. So I hit Enter, it  looks like a normal Python interpreter. But it's   not because I can do from products, the models  import product, right. So I can do these kinds   of imports, I can import classes, just like we  sort of did in the admin, right, I did a relative   import in the admin. This is closer to an absolute  import inside of the shell. So I go ahead and hit   enter here. And I can do product that objects  that all this is a built in Django command,   we'll get over this sometime in the future. But  for now, if I hit Enter, I see that there's only   one thing in here, right, there's only one item.  And that's because I only saved one in the video,   that's all I did, you might have done it.  Otherwise, you might see a lot more there.   And that's cool. If you have that means that  you're experimenting, that's awesome. But for me,   what I want to see is more I want to actually  create them. Right here in the shell, I want to   have the ability to do those commands. So it's  simple, we just do product that objects create.   And then we want to create new ones inside of this  command itself inside of create itself. Again,   this is built into Django, this is default by  Django standards, right? So in models, we look at   the things that are required for this product, we  have four fields that are required. So I can pass   those four fields in here as title, new product,  two, right? And description as another one,   right price being, you know, whatever price,  and then finally, summary being sweet. Okay,   notice each one, each argument in here is  a string itself, right? So I did that on   purpose. They're all strings. And that's how I can  create a new product. I hit Enter, it creates it,   I can press up and enter again. It's creating  new a new product. Right. And if I did that   product dot objects at all, again, what I see  here is a list, also known as query set. Again,   we'll get into that later. But it shows us all of  those new products created. Now, assuming we still   have our server running, which I do, you can close  it out with Ctrl. C, but if I just go ahead and   make sure that my servers running, I can come back  into my admin, right? So you log into your I mean,   you see this, you go to products, what do you  know, I've got all of those products in there.   So that's another way to actually create things in  your database, just by using a command instead of,   you know, clicking through and going  through the form and doing all that. Pretty,   pretty awesome. So we still have a lot more to  do, obviously, we want to see this in another   form. But before I jump into another form, I want  to see actually, how do I realistically create a   model that isn't so convoluted, like I shouldn't  actually pass a string for price, it should be   in the actual decimal, right. And perhaps  the title shouldn't be this long text area,   maybe it should just be one shorefield. So there's  definitely things that I need to change to this   product model to make it better. That's something  we'll do in the next one by adding new fields.   So now, what I'm going to do is actually start  over on these models, I really don't like what I   did here. So in order for me to start over, I can  delete all the files in the migrations folder. And   just leave it in there, that's fine. also delete  pi cash if you have it there. And then also,   I'm going to delete my sequel lite database. Okay,  so back into my models, I want to change these   fields to something different, what I just did was  something you'll do often while you're learning,   right, you'll delete those migrations, and then  you'll delete that database. Sure, you might lose   some data. But that's no big deal. That's part of  the learning process. And that's actually really,   really important to do. So with these fields,  I want to transition them into being something   more realistic to what they are. So let's go ahead  and look at the reference in the docs themselves.   So Django project.com. Look for the model fields,  field types, you can just do a quick Google search   for this. And you'll see the reference for all  the different field types. And what we actually   used so far was just one of them. As you see,  I'm scrolling. There's a lot of them. So I used   just this text field, that's one of the very many  that we have in here. So let's go ahead and use   a few different ones. First of all, the title  field should be limited to how long it is. So   I'm going to change it to a char field. And I'll  add in something called max length. And I'll make   it at most 120 characters, that's still a fairly  long title, but that's what I want it to be. And   when you use a char field, you have to use max  length. So max length equals two required. Well,   I'm gonna leave it out for just a moment and  save it. And now I'm going to go ahead and try   and run my migrations, right? So I'll go python  manage.py. Make migrations. I get an error, says   char fields must define a max length attribute.  I just mentioned that was required. But luckily,   Django will tell us if something's required, once  I save that some of my errors go away. Right?   description text field, that actually makes sense.  But what if our products, we don't necessarily   want to have a description, then I can say blank  equals to true. And I can also say no equals to   true. I'll explain these deep the differences  between those two in just a moment. Price,   what should our price field be? Well, should it  be a text field? Or should it be? Well, let's   see if there's a decimal field, hey, what do you  know, there's a decimal field and a float field,   I'm gonna stick with decimal field. And this is  where the docks come in and make things a lot   easier for us. This will show us what's required.  Okay, so what's in here is required. So these two   things are required right here. Whereas if we  go down a little bit, it says duration field,   we're not going to use that. But there's nothing  in there that's required. We've got email field   that has a requirement, but it's already in there.  It's already built in. So this will take some time   getting used to but that's essentially what's  going on with the docks, right. But it also shows   you inside of the docs that it has those required  arguments. In other words, let's go back in here   and change this just to decimal field. Let's save  it. I save it, it's going to run these errors,   right? It shows me these errors. It tells  me exactly what it is. But so does the docs,   right so the doc says back digits and decimal  places. So let's go ahead and add those for a   product decimal places is gonna be two, like you  know, it's not going to be three decimal places.   You don't have three decimal places of sense.  And then max digits, as in the number of digits,   this will allow, like 1000 digits is actually a  lot for a decimal number, right? So just do that   in your math in your head, what's 10,000 digits?  in dollars? That's, that's a lot. Right? Cool.   So I now have a little bit more robust fields.  Summary, I can leave it as a text field as well.   Maybe I want summary to be in there by default,  maybe I wanted to for sure be in there. But   I'm gonna go ahead and get rid of that default.  I'll explain the default thing in just a moment,   most likely in the next video, but I will explain  what's going on with that here shortly. Okay,   so I save this. And now what I need to do is  actually run my migrations, again, remember,   every time you change models.py, you have to  run Python managed up py, make migrations, and   then Python manage.py migrate. Now, I deleted the  database. So that also means that I need to run   create super user all over again. And I'm going to  leave it in as CFE type in that password of learn   code. And there we go, my server is still running  through all of them, my server still running,   I refresh in here on the Django admin, I still  have to go back and log in. And I see that I   actually don't have any products anymore. But  if I go to add a product, the layout of it has   already changed. The title can't be some long  title, I can say, new product, and description,   I can write stuff if I wanted to. Price has now  a number item in here. So I can actually write   numbers 2989. And I can add a summary, some  new summary, exclamation mark, I hit save,   what do you know, not a whole lot different. Okay,  with that in mind, let's just see it in the shell   too. So Python managed up py shell. And we'll  just go ahead and do from products, dot models,   import product, does the exact same thing, it's  just going to the location to where that product   is, we can enter product objects, create title  equals to newer title, price. Now we can put   actual a decimal number in here, no string. So  239 99, and then summary. Now string, awesome.   sauce is awesome. We hit enter, it looks like  it created it and no problems, we go back into   our products. In the admin still running, we see  that we have a new product in here, all of that   stuff was saved. So it's bringing those two things  into conjunction with each other. So we're already   starting to save stuff, we already hopefully  see how easy it is to map data in Django.   This one, I'm going to make a new change to our  model with out deleting the database. So all of   the migrations for that matter. So that means that  we want to actually know a little bit more about   what's going on with both of those things. So when  we run, make migrations and migrate, it syncs the   database with our model. But if we add a field  to our model, the database doesn't know about   that field. So we have to make sure it knows and  make migrations and migrate often allows that to   happen. But it also introduces a whole set of like  question marks like the field that is being added   into the database. What about all of the previous  things were that were in that database? So let's,   let's see what I mean. Right? So if I jump into  the admin, I see that I have these four fields   here, right? But if in my models, I decided to  say featured field, right, and I wanted to use,   let's say models, dot Boolean field, okay,  so I'm now trying to add this Boolean field,   but this particular objects, this saved object  has no idea about this field, right? All future   ones might, but this particular one doesn't. So  if I went ahead and save this, and went to Python   managed up, py make migrations, right? So you  do that, by default, you get this error, says   a non nullable field. I did mention that I would  say what these things meant. That's what this is,   right? So if I said no equals to true here, this  error would not have happened because it would   have said all of those old values, just leave  them empty in the database. They can be empty,   that's fine. No worries. But I don't want to do  that. Instead, what I want to do is I actually   want a value for those old items in the database.  It could be one item, it could be 10,000. Django   actually doesn't know how many items that are in  the database that haven't been set yet. Again,   it could be zero items. Now, there What Django  is going off of is this migrations folder here,   it's going off of this initial value. Notice this  initial one right here, it's checking against   what's in here. For this model, it's saying, hey,  the new field that you're adding this new field   right here, isn't in this initial description,  it's being added to it. So we're going to assume   that the database needs to know about what's  happening there. So we need to tell the database,   what default things we should do. Now, you can  do that. There's several actions you can do here,   right? In the code, you can say no equals to true,  or you can set a default. Or you can do both,   right? So you can have a default in there, right?  So Knoll equals a true or default value. In this   case, it's a Boolean field, which means either  true or false, you could say default equals to   true. So you could absolutely hard Right, right,  those and the code, or you get this error, and   you can provide a one off default, for all of the  previous things that were in there. And I'm gonna   say one, and literally say true, right. So this  means that everything that's in the database, it's   going to go through all of them that's already  currently in the database. And it's going to save   those things as having a field of featured with  the value of true, as opposed to false. I hit   true. There we go. Now that make migrations, what  that ended up doing is it developed a file for us   a migrations file, and this is it right here,  the database still doesn't actually know about   anything, right? It doesn't know about this field  still still, because we didn't run migrate. So I   can actually come back into my Django project. And  I get this think no such column, he goes to that,   right. So that's an error that you might see quite  often, I know, you will, actually because people   forget about this. So we want to run Python  managed up, py migrate, because we always run,   make migrations, and then migrate. And then there  we go. Now we have a change actually made. And as   we see, all of our old objects that are stored  in the database have featured as true all of the   new ones. There is no default in there. Cool. So  that's awesome. What that also means is then in my   models, this summary, what if I wanted that to not  be required anymore? Well, I can say blank equals   to true. But let's go ahead and say no, equals to  false and see what happens here. What did I do,   I made changes to the models. So what do I  have to do, I have to run Python managed up UI,   make migrations, and then Python managed up,  py migrate. Cool. So now that I've got that,   I come back in here, I refresh. summary is no  longer bold. And I can now leave it empty in   the database. So if I change blank equals to  false, save it, again, run, make migrations,   and again, migrate, I can go back in here and  refresh. And notice now it says that it's bold.   So if I'd save and continue, it'll give me this  field is required. So all this is doing is blank   has to do with how the field is rendered, no has  to do with the database. So if the blank is false,   meaning that it's required, then it will  render as required, that has nothing to   do with the database, as we see with these two  things here. But no being true or false means   that the database can be null or empty in the  database. Cool. So that is changing some items   in the model. This used to be very, very hard. And  even if you feel like it's a little challenging,   doing this several times, breaking it, the  leading the migrations, fold the migrations,   in here already deleting the database, running  all of that stuff all over again, doing that   several times, will really get you comfortable  with models, I promise you it will and then try   to explain it to somebody try to explain to a  friend, make a video, try to explain all of the   things that I just did. Go back and reference  them, read the docs, whatever you need to do   to really better understand how this basic stuff  of models works. So there's definitely more stuff   we can do in models, but I'm going to kind of  leave it as is. There's other things that Django   does really well that we want to start talking  about. And that has to do with views and URLs.   So we want to change this default homepage to  our own custom homepage. How do we go about doing   that? Well, we do this by creating a class or a  function based view. So a view means that it's   going to handle our request. I'll get into all  of that later. But right now what we want to do   is just illustrate the purpose that we're doing.  So I created a new app called pages. I added that   pages to Settings installed apps are you Want to  get in the habit of doing that whenever you create   new apps, but you should know how to do that by  now. That's why I didn't do it. Okay. So inside   of views.py, we see that there's nothing in here,  this is where you're going to be creating all   sorts of things for your pages. Think of views  as a place that handle your various web pages.   Just think of it that way. And we're going to do  this using either functions or classes written in   Python. So the first one I'm going to do is just  a homepage. And basically, it's just very simple   function, it's home, you give it a name, whatever  name you want, I would probably say that mostly,   you'll probably add view to it. Like, you're  not going to call it home page, without view,   right. So I'll get into view and all that stuff  later. But let's just call it home view, okay.   And then it's going to return something, we want  it to return some HTML. So let's say for instance,   I want to just say, h1, hello, world. Now, if  you're familiar with Python, you'll know that   this is just a very simple Python function. It's  actually nothing in here is related to Django,   so we need to change it to be related to Django.  Now, this string right here has HTML in it. This   is a string of HTML code. It's not actual HTML  code. We'll talk about that later. But this is   definitely useful if we want to just have one  string of HTML code for some reason. But how   do I actually make this functional? To do that we  use from Django dot HTTP import HTTP response. And   HTTP response, we can just call with that string  of HTML code, just like that. We're really close   to making this an actual functional view, or  functional page. So I'm going to go ahead and   add RS and keyword arcs in here. If you're not  familiar with arcs and keyword dogs, I definitely   recommend that you look that up on Python, this is  Python specific. If you're not, don't worry about   it. It's okay, you can look it up. But for now,  we can just play around with this. Okay, so I've   now created a function, all this function does is  return back some HTML code that says, Hello world,   but it returns it back in something called an  HTTP response. Okay, so let's actually make   this work. I'm gonna save it. And I'm gonna hope  for the best refresh here. It doesn't work. Well,   what if I tried different page like ABC, that  also doesn't work? It says page not found. And   it says something about URLs? Well, this is where  we actually wrap in our URLs. This is where URLs   comes in. And when we went over the settings,  we did mentioned about the URLs right here. So   URLs are in try Django dot URLs, or otherwise, the  settings module or the settings folder. Inside of   URLs, this configuration folder has settings and  URLs in there. And it has one that we've already   been using, which is admin. But that's the only  path it actually has. So now what I want to do   is actually import that view to work with my  URLs. Now, you already have some of this stuff   in here. Right? So this is actually written for  us. So I can go off of what they have written   in a similar fashion by saying from pages,  right, so pages would take place in my app,   import views. And then I can quite literally  add this URL pattern, like it says in the code,   or in the comments there. And I didn't call  it home, but instead, I called it home view.   Right? So there we go. I'm just going off of what  they've given me home view, and home view. We save   that. And let's go back to our homepage. Hello  World. Cool. It's actually working. There's a   couple things that I don't particularly think  is a good idea with how this is written. Is   that what if I wanted to use the product views  then, and I went from products, import views,   things get confusing. So don't do it this way.  Go views import home view, import the actual view   that you want to use, and then just put that down  there. Okay. So we save that and what do you know,   the same exact response? Wow, that's fairly easy  to work with. Not a whole lot going on here.   Let's talk about URL patterns and how this  portion works in conjunction with our view,   now URL patterns, you notice that I Have  this empty string that's in this path. So if   I actually copy this and paste it down here and  say home and put a slash at the very end of it,   and save it, I can actually go into home. And  that same thing will come out where if I use a   different page like ABC, that won't show up.  And the page not found is because we haven't   routed a path to that view. Right. So let's say  for instance, I want to call this contact. And,   you know, we can, we can actually ignore this name  stuff for now. But if I want to call this contact,   sure, it could actually go to that same homepage  view. But really, you would probably want to have   another one called contact view. And again, we'll  do ours and keyword ours, and then we'll return   HTTP response. And then we'll just say, h1 and  contact page and close out that h1 tag, and then   we would import that as well. Just like that. And  there we go. So that would give us that contact   page. pretty useful. Now what's actually happening  inside of this path, right? So the URL when you   go to a Django page, right, so we we go to a  Django page, right here. And Django knows that   something is being requested, that's different.  So the first thing that's being requested is just   this homepage. And then if I go to another  page, like contact, that's a new request,   and it's getting that item, whatever's in there,  and Django is smart enough to know, hey, that URL   is being requested, look in this urls.py, or that  main configuration that we have set up by default,   it's going to look for that URL. And then with a  matching URL, it's going to look for a view that   is made to handle that URL. Right. So we already  have those views that were made to handle it,   you know, we can have as many views as we want.  It's completely up to you. And in fact, your   project might have a lot of views, right? So like  social about, whatever, like all of those things   you can absolutely start playing around with. And  I recommend that you do I recommend that you take   this and play around in the sense that, hey, how  does this actually work? And how can I make all   of my own pages? Now there is a critical thing  that is missing here. But I'm not gonna get into   that just yet. What I will say is that remember,  when we go to a URL, we're requesting something   from that URL, it's kind of like knocking on  the front door of somebody's address. I mean,   it's not a whole lot different than that,  except this is digital. We're going there,   we're knocking, we're asking for something,  or we're requesting something. In this case,   we're requesting a web page that's at that URL.  So what's actually happening is on these views,   we have ours and keyword ours to just capture  everything. So if I actually print it out,   let's go ahead and print out ours and keyword  ours. And go back to that homepage. And look   into our terminal. We see here are the things that  are being passed. We have this Ws gi request, huh,   I'm requesting something. So that means that it  actually is an argument that's coming through   here, I can say request, and then RX keyword  Rx, right. So each one has request coming in   here by default. So if I go back refresh, now my  RX and keyword ours are empty. And my request is   absolutely in there. So I can print out that  request. And we can see it. So what does this   request do exactly? Well, there's a lot of  different things that it can do. But one of   them that's important for us is request the user.  So this is where that authentication stuff comes   in. This is where logging in your users come  in. But this is also how our views can access   that. So if I refresh in here, I can see that,  hey, my CFA user is logged in. If I opened up   an incognito window, or just another browser or  logged out, I would see that it's an anonymous   user. It's not somebody that's actually logged  in. So both things are actually valid. And they   are really good to know. Because then I can do  all sorts of stuff with this request user. Now   that's a little bit more advanced. So before we  get there, I want to make this basic web page   or these basic application work better for  us, like, so far we have this HTTP response,   and it's rendering out of HTML. And that's great  and all but you know, you might be familiar with   HTML. Hopefully you have some background HTML Just  having an h1 being rendered, that's not very good,   like notice, like my head is empty. It's just  h1. That's the only thing that's coming back.   So now it's actually a really good time to  start talking about the Django templating   engine. So we can override this HTTP response with  a nother sort of thing called Django templating.   quick recap, we go to a URL, it's like we're  knocking on someone's door requesting something,   the server or Django returns a response to  us. That is the process that always happens   with correctly configured Django projects. Now,  when this happens, Django recognizes what URL is   being requested or, you know, that web address is  being requested, it breaks it apart, figures out   what function is going to respond to it, right.  And with that function, we want to respond with   some sort of HTTP response. The basic default one  is this just HTTP response. And we can pass in,   whether it's HTML itself or just a string, it  doesn't matter, we can return HTTP response. And   we can even return it being nothing like it could  be absolutely empty in here, and it would still   work. So this is still a valid page. But what we  want to do is, instead of writing in strings here,   we want to use some built in shortcuts that Django  has. And you may have noticed that shortcuts,   import render was in there by default. So  when you create a new app that's in there,   okay. So I want to actually be able to use this  itself. So instead of returning a response,   what I want to do is return render, and it's going  to take in a few arguments. One is request, the   request argument that's being passed. One is going  to be a template name, let's say for instance,   home dot html. And then the last one is context.  Or for now we'll just do an empty dictionary,   we will talk about context later. So that's how  you would be able to return some sort of HTML   template or HTML document, either way. So how do  we actually find? How do we actually find this?   Like, where's that located? If I save this and  refresh in here, I get this error template does   not exist. Well, it certainly doesn't. We haven't  actually created it, right. And it's looking for   it throughout our site, but it doesn't actually  know where to go. So we need to create a location   for it. And that's what we'll do now, inside of  our src folder in the root of the Django project,   we're gonna make a new folder in here called  templates. This folder is going to hold all of   our templates as we see fit. So inside of there,  we're going to go ahead and do home dot html,   making that new file. Notice templates is online,  with pages, products, and the Django configuration   folder, as well as manage.py. So I'm gonna put a  home dot html in there, and I'm just gonna say h1,   hello, world, close off h1, and then do a p tag.  This is a template. close out that p tag. Okay,   so we save that seems like things are looking  good. We made a template folder home dot HTML is   in there. We want to render it out. Save it. Let's  go back rerun it. Huh. template does not exist   still. Well, this because we haven't actually set  up Django to know where these templates are. I   mean, I didn't name it templates. But that's an  arbitrary name. That directory is an arbitrary   name. It is a best practice name, but it is still,  I just made it up. Okay. So in settings.pi, then,   remember how I said we were going to come  back to templates if you watch that video.   That's this. So we want to actually put  in sign of our ders or our directories,   where this directory location is. Now I could  have hard coded to your path to templates. Let's   do that. So let's go ahead and say pwd, here is my  normal project here. Right. So that's to the root   of the Django project. All I need to do is add  templates here. As in the name of that folder,   I hit save, and refresh in here. What do  you know, our templates are looking good,   they're actually in there. But if I sent this  to you on your computer, it's not going to   work unless your user is CFE. So what we need  to do is pretty much copy what we did here,   that's actually fairly straightforward. But with  some minor exceptions. Basically, I want to make   it OS independent. I want to make it allow it for  me to send this code to you and it's still work.   So it's b o s path that join base dir and then two  templates. So I'm just joining that base directory   where manage.py is with the templates directory  that I just created. And refresh there. It's   still working, that templates still showing up. So  what this allows me to do then is to make multiple   pages like about dot html, contact dot html, and  so on. And then I can just quite literally bring   in all this code here, and say, contact and about.  And then in my view, just like I did on home view,   I could just read, change these about and  contact to content to the correct name, so   about an HTML and contact that HTML, I save that  refresh, everything's looking, okay. Go to about,   hey, look, and cool. So it's rendering HTML.  Notice that it doesn't have a dot html here,   right? So it's, it's not actually like rendering  out that raw HTML file. It's, it's actually going   through Django, and Django is rendering out that  HTML. That's pretty cool. So if you've worked in   web design before, you'll know that that dot html  being gone, makes these URLs so much cleaner,   and it's a lot easier to navigate and share.  And it also makes it look more advanced,   in my opinion. Okay, so now we have a way to  render out HTML documents. But you might see that   there is a lot of repetitiveness that could happen  in these documents. So we need to talk about some   basic inheritance stuff with Django templates.  And that's something we'll do in the next one.   Time to talk a little bit more about the Django  templating engine that we are actually already   using, but we want to learn more about it. So if  I look at something like this, we've got two curly   brackets, request dot user to more curly brackets.  This is something that Django does by default,   and it actually will render out that relative  information. So we actually refresh in our   homepage. And I see that CFE user, that's my  username. And if I open an incognito window, I see   anonymous user, that's expected. So that's part of  what's built into the templating engine, we can,   we can use the user model in it, right. And I can  also say.is authenticated, as in is logged in. And   it'll say true or false, depending on if they're  logged in, right. So there's definitely a lot of   things we can do there, which we'll talk about a  lot more soon. So make sure you subscribe to get   everything. But what you also should notice is  that our views are rendered out three different   HTML pages that actually might share attributes  across each one, let's say like a navigation bar,   or more importantly, some metadata, like,  you know, if we inspect the element here,   and we saw, like, you know, the title tag, or the  description tag, or other metadata that we might   need to implement in here, or some CSS data, I  mean, there's a lot of things that each one of   those pages would actually be able to use. So  this is where template inheritance comes in,   and where it's really useful for us. So what  I want to do is create a root page, the page   that all these other pages are going to borrow  from. So go ahead and call it based on HTML,   based as your HTML is convention, that's how  you're going to want to call it so and you're   going to want to make it a actual HTML document.  So doctype, HTML, and then HTML, close off HTML,   and then body and body. Okay. And then we  want to do a head tag here. And in this case,   just to show that this is actually working, we'll  go ahead and put a title tag and say, coding for   entrepreneurs. is doing try Django. Hey, okay.  Not really that clever, but it is something.   So we've got our head tag, our body tag, we have  some HTML in here. We've got some stuff. And now   what do I want to do? Well, each one of these  pages, I want to also have all of this stuff,   the exact same stuff. How do I do that? Well,  what I can do is come inside of this base dot   html, curly brackets, percent, block content,  percent, curly brackets, percent curly brackets,   block or curly brackets, percent block or rather  in block. Okay, so this syntax might look a little   weird to you. But basically, it's saying Like,  hey, whatever is in between here, whatever comes   in here, let's just replace it. So replace me.  Okay? That's all I'm saying, we're going to use   these blocks these exact same blocks on any given  page. So let's say for instance, this, I'm gonna   go ahead and cut this out. And say, just like  that. So I've got a block here. And that's the   content that's going to be it's essentially going  to be copied here, brought in right here. And all   I have to do to make all that happen is extends  based on HTML. Again, these curly brackets,   percent signs, it does definitely can get a little  confusing. So make sure that you are testing this   on your own to make sure it's working. Okay, so  I've got now a new thing for home dot html, back   into home, look at my title tag, if I refresh, and  now change to coding for entrepreneurs is doing   try Django. So that title tag actually did change.  And it's based off of this base dot html. So let's   do that again, on about instead of about curly  brackets, percent extends based start HTML. Okay,   so this is now pulling from based on HTML. If  I saved it, just like that, and went into that   about page, it just says replaced me. Ah, so it's  rendering out this default page. That's all it's   doing. So in order for me to actually replace  whatever block is in there, I have to use it,   I do block content, curly bracket. So curly  brackets percent block, that is the Django related   stuff. Content is a variable that I created. And  then we do in block to close it off. You might   also see in block content, that's okay, too. So we  save that and we refresh. And that is now changed,   the title has changed. So we now have template  inheritance. And then, of course, that final thing   would be true with context as well. So again, we  do extends based on HTML, and then block content.   And then finally, in block, just like that, so  the content that I'm actually using is right here.   But now each one of those pages is uniform.  In Django, this makes a lot more sense when   I use something like a navbar. So let's just go  ahead, and I'm just going to use h1 or an h1 tag,   just to show this is a navbar. Not to get into  too much of the HTML here. But this is a navbar,   it's all about page. It's on my contact page,  it's on my home page. Right. So it's definitely   the same thing all across. And that's how this  inheritance actually works. And I will say that,   you know, if you change this to blog content,  main or something like that, and then I save   that every single one of those pages would change,  right, because I'm not actually rendering or I'm   not replacing the correct block, and each one  of those pages, instead, I'm replacing nothing.   So they just don't do anything, which is really  cool. That actually makes things a lot easier   for us in the long run. But this might be a  little tricky to get your head around on how   this actually works. So what I do also recommend  that you pause the video or stop now and change it   to another content area, and do several blocks  in there to see how all of that works. To make   sure that that you have a better understanding of  how this inheritance is because it definitely is   a little bit trickier than just rendering out  an HTML page, just a blank HTML page. But it   is important. So we will still do more stuff  on Django templates. But that's it for now.   So what inheritance allows us to do is to remove  redundant code that we need in many places,   or we're gonna talk about in this one is the  include a template tag, so we can do this more   of the same, just on a little bit more of a  different level. So what I mean by include is,   sometimes you'll have a nav bar or a navigation  bar that you might want to have in multiple   places. So to allow this to be showing up in  multiple places, or allowing me to edit just   that navbar not having to go into the base every  time, I can actually come into my templates, and   let's just make a brand new one called the navbar  dot html. And this itself will just be the navbar   it's not gonna have anything else, it's not really  going to be doing template inheritance. Instead,   what we're going to do is have a navbar of some  kind, right? So if I just wrote nav and then did a   ul in here, and you know, did some navbar related  things. I'm not Can't make a real navbar really,   but let's go ahead and just say brand. There  we go. So we've got a simple nav bar with just   brand. And let's say contact, and about. Okay,  so we save that and go back into base dot html.   And let's get rid of this, this is a nav bar  thing, right? So we just want to go ahead and   use include. So again, curly brackets, percent  sign include, and then the path or where that   that actual HTML document lives. And we'll  say, simply just nav bar dot html, you know,   so this is very, very similar. Now very similar,  it is identical to our views that we created,   right? So whatever we put here would be very,  the very thing we put here. So that same path,   we'll get into that more later. But this is how  we can include an external template into any of   our templates. So we save that and refresh. And  there we go. So we now have a navbar. Granted,   it's not a very good one, but it is a navbar, that  will show up on all of our pages. Cool. So this,   the reason you do this is once your project gets  complicated, once you have like a big old project,   you're gonna want to use this include, because  then if I need to make a slight change to my   navbar, I can just jump in to navbar dot html.  Pretty cool. Very useful. So now all we want   to do is actually talk about context. So like,  how do I actually use things beyond just that   request user that we've seen before. So I want  to actually add in some new data that's coming   from other places. So I'm not hard coding it every  time, but rather, it's coming from somewhere else.   So the main purpose to use templates in Django  is not so much for inheritance, including,   and granted, it does the things well, and you  could make a pretty cool website. But what we   really want is data from the back end, we want  data from the database that's being rendered out   inside of one of these templates, we want to see  that we kind of teased it a little bit with that   request that user a few videos ago. But I want  to actually go a little bit further and say, you   know, maybe I want to change the title of a page,  or I want to have different content in there based   off of a different user. And we're going to work  towards that. But the initial thing that we have   to understand is what's called template context.  And that's what we're going to cover in this one.   So let's go ahead and jump into our views and  I leaved are left out this dictionary, right,   so it's an empty dictionary right now. And that's  actually where we can pass in context to our   template. Because what Django does is it takes our  template, and the template context, mashes those   things together, renders it, and then sends back  just raw HTML to the browser. We'll see what that   means in just a second. But that's essentially  what's happening. It takes the template, it takes   some context, mashes those things together, turns  it into regular HTML, and then the user sees that.   Okay, so what do I mean by context? Exactly? Well,  context could be any data type, right? So let's go   in our, let's say, our about view, right? So let's  make a dictionary just with standard old Python   dictionary and say, my underscore context equals  to a dictionary. Alright. So if I grab my context   here and put it in and replace that empty one,  we've got the same stuff going on right now. Okay,   so I said that I wanted to change my title. So  let's go ahead and just have some arbitrary key,   meaning I'm making up this key. And we'll say,  my text. And we'll say, this is about me, or us,   whatever. Okay, so this is now my context, all of  this stuff is arbitrary. I made it all up, as you   probably could guess. But we've got a key value  pair here. So it's a just a standard dictionary,   with a key as a string, that's a standard thing in  Python. And then I can use a string as the value   or I could use something else like, number or  rather, let's say something more like my number.   And we could do 123, right. So I can use strings,  I can use numbers, I can use other dictionaries,   which I'll let you play around with the data  types yourself, because that's not really   what's important. What's important is how we  actually bring this into context into this about   page. So since I've got this context, I have this  dictionary in here, I've created a custom one for   myself. I want to bring this into that template  and take a look at that template. So I have   two different key items here. So let's go into  about about dot html. And let's also make sure   our project is open on that page is So we'll go  to about here. And there we go. So we're in that   project that's rendering out this template. And  how I actually render out any sort of item that   I passed in as context, I would normally normally  bring in my, you know, something like a p tags or   general HTML here. And then whatever context  I want to use, so we use these curly brackets   twice. So curly bracket, curly bracket, or braces,  space, we'll put something in the middle there,   and then curly bracket, curly bracket, and then  we're done. Okay, so what is it that I need to go   in the middle of here? So this is called a context  variable? Right? So a context variable, meaning,   what variables did we pass into our context? And  what can we use? We already seen request that user   so that is something that's already built in  there, right? But how do I actually access the   things that I pass through? Well, hopefully, you  have some intuition about this. If not, it's okay,   you'll develop it. We have these two variables.  So our keys become the template variables that   are inside of any given context that we pass.  So now what I've done, as I said, Hey, Django,   we've got this about dot html page. And then we  have this context, I want you to mash those things   together and produce something that I wouldn't  expect. So in that context, back in the HTML,   we can say, my underscore text, and that right  there should render out this key and that value,   right, so it's taking this key, that's what we  used, and it's going to render out this value,   we can do that same thing with my number. So  back into about, we can say my text, underscore,   or rather comma, curly brackets, curly brackets,  or braces, opening close, Sublime Text does it for   us, but you know, if you're using a different text  editor, you want to make sure that it's done this   way. And then we'll say my number, we save that  we go back into our about page, we refresh it. Oh,   we're not actually getting anything. Why is that?  Well, it's actually possible that I didn't save my   about view context. So I need to make sure that  I'm always saving everything. Right. So I mean,   if it's empty, that means it didn't pass  through, it means that the context was empty,   it means that this stuff wasn't actually set.  It's a pretty cool error to see right off the   bat. It's not really an error, it's actually a  feature. But if we refresh in here, now we see   that data coming through. So that at its simplest  form, is template context. And it's, again,   just a really quick thing, we make a dictionary  of the template context that we want to pass. And   then we pass that now one of the things that you  might be wondering is saying like my list, and how   do I actually work through with a list? So if I  said, 123, you know, in some numbers, or strings,   it actually doesn't matter? How do I actually look  at this list? Right? So I come in here, and I say,   my list, I render out that list. Well, that's nice  and all, but that's not how I want to see it, I   want to see it in maybe an actual HTML list item,  right? Perhaps that would be a little bit better.   So this gets a little bit more complex. And that  gives us the discussion of what's coming next.   We left it off where we passed in some template  context of a list. And we want to see that   actually rendered out, we want to actually look at  what that list is in a different format. Right. So   the format I want to see is something like this.  So let's do a ul, inside of our template and   do a list item. So item one, and then close out  that list item list item. Item two. Okay, so how   would we go about doing this? There's, there's a  couple ways that you can do it. But the main way,   let me say a couple ways that you could do it one  of the wrong way, let's do the wrong way. First,   the wrong way would be to come in here into  your view, and render out the list as different   variables. So in other words, saying like, for  item in some list, so let's just do another list   here. And then doing my context. And something  like this item A equals to item. Granted,   this is not the greatest because it's only going  to end with that. But essentially, you don't want   to do this, you don't want to go this route. But  we are starting to move towards what we want to   do in the template. And that is we want to create  a for loop within the template. So the templates   themselves can have this same sort of flow, we can  actually go into a template, and we can run a loop   on any given context, object or constant context  variable. So to do that, we would just go ahead Do   curly brackets or braces percent for and then some  arbitrary you know variable name, I'll go ahead   and say my sub item in my list. And then curly  brackets. And with templates, it is different than   Python, it's closer to how like HTML would work.  So if you open a for loop, you must close a for   loop. So there we go, we have a way to actually  loop through this stuff. And then all I have to   do is put a ul on the outside of it, and then a  Li on the inside of it. And then we can just use   those curly brackets again to braces, and do my  sub item. And we save that. And what this will do   is actually iterate through every single item in  my list, assuming that there's stuff in that list.   So if I refresh in there, now we see those two  new things, right, so we actually see these things   that are rated out. And they're shown up here. And  there are other additional features to looping in   here. One of them being like for loop, counter.  And this allows us to see what iteration number   we are currently. So if I refresh, I see that it  goes 123. Right. And granted, in my view, if I   were to change the order, or change the values,  and even have, you know, ABC streams like that,   stuff like that, all of that will come through.  It's pretty nice. I mean, it allows us to do   all sorts of things inside of our template that's  based off of what's coming through our view. Now,   don't get me wrong, we still aren't seeing data  from the database. Like we're still hard coding   all this stuff, like I do want to work towards  where I can actually see data from the database.   But there's still a few more things that I want to  do with templates and views before we get there.   So now what we want to talk about are conditions  in a template. That is an if else statement inside   of our template itself. Now by and large, you  want to make sure that your logic is already   handled in your view. That's a general rule of  thumb. I'll get into that a lot more later when   we get more advanced. But basically, if you're  going to be doing a lot of if else statements,   you're going to want to do those in the view and  change your context that you're rendering in the   template, you don't want the template to do too  much of that work. But there are cases where you   will want your template to do it. And I'm going  to show you a very basic example of that. But I'm   also going to give you a little bit of a warning  with your variable naming with templates. Okay,   so the first thing is, when you have your context  here, and you render it out, and let's say for   instance, you do have a list like this, we're  going to want to be very selective about how we   render that inside of our for loop. So in other  words, if I changed, let's say, for instance,   my text to being ABC, and then inside of my about,  I have ABC here, and then I change my variable in   my for loop as ABC, the things get a little hairy,  and they might render fine, right, so it renders   out fine. But then when I actually want to do a  condition, such as if ABC equals 2312. You know,   if that's the case, then I might want to rethink  on how I actually named my variables. Because   they are I mean, then this is already looking  tricky. Like, I'm already unsure of what's going   on. So let's keep this in as my text. And my text,  something like that is frustrating when it happens   when you don't catch it. But it is something that  you'll gain the skill of overtime, I promise you,   it's just about recognizing how you name  variables. And this is true in Python in general,   right. So sometimes you might name a variable, one  thing, and then it's rendering to something else.   It's also true with functions and classes. I mean,  I've seen it happen a lot. And it's happened to me   so much. So I just wanted to bring your attention  to that because of what we're doing right now.   Okay, so going back into this about page, I have  this condition here, right, so I actually created   one, and it's really simple, we just call an if  statement. So percent if some variable or some   thing that would be able to compare to another  thing, or more simply if something is, you know,   true. So you can also pass in a context variable  in here. So back in my view, I could just say this   is true, and just set it equal to true, right? So  I can I can still use that. So these conditions,   what they allow you to do is just evaluate whether  or not this statement is true. And you can use   things like equals equals, just like I have here.  And then inside of that block inside of here,   you can render something in particular. So let's  go ahead and render that something in here. And   you know what I'm going to throw in a another  little conceptual thing that we'll take a look   at later, let's just say add 22. So I've got a  straight arrow, also known as a straight line,   also known as a pipe. And then we just type out  ad, colon, and then whatever number we want to   add. So we do that, and then we refresh in here.  And I've got stuff rendered out. So notice that   the third iteration goes twice. Now this is  because I have my if statement, but then I   also have the default or what I used to have. Now  what we actually want to do is, instead of having   the default like that, we would just say an else  clause in here, and bring in that else clause,   just like this. That way that the list can be  iterated through. And if ABC is equal to 312,   then it's going to render that out and add 22 to  it. So we save that and we refresh. And now it's   still only those four items, except that one  condition is now met. And it's allowing us to   do some addition. Now, we can also have another  condition, right. So if I came in here and wanted   another condition, you might be tempted to say  something like else if but in Django, it's lF,   just like that. And that's how we would do another  condition. So we can check that other condition.   And let's just say if it's equal to ABC, or  that single string, so if it's equal to ABC,   we can keep that for loop counter in there if  we want. Or we can say, this is not the network.   ABC. There we go. Nice little ways of doing  conditions. And you probably are wondering,   like, what the heck is this What's going on here?  That is actually called a built in template tag,   filter. So every single one of these items  is called a, it's it is a context variable,   but it's a template tag itself. It's like  rendering something out that's specific to   Django templates, and the templating engine. And  all this does is it does a very basic function   on that context. Well, we'll play around  with that a little bit more in the next one.   By now we've used several built in template tags  that are provided by Django, we've used extends   as a template tag, we've used block we've  used for, like the for loop we've used if,   but this is an it right, we've actually have a  lot more. If you look at the documentation itself,   there's a whole list of items that you'll see  four built in template tags themselves. You know,   we just talked about block, but there's one  for comments. So if you want to write notes,   you can write comment as a template tag, you can  cycle through things, that's something we haven't   actually covered. But it is something maybe to  play around with. Or if you want to see it in   particular, please let us know in the comments.  I don't actually use cycle that much anymore.   And I'll explain why in just a moment. of what  we've seen for loops we've seen include we've seen   extends, right? So we have all sorts of items in  here that allow us to make our templates that much   more valuable. And then there's another thing that  I kind of tease that we'll talk about right now,   which is filter. So so this is a filter, all it  does is take whatever this value is or whatever   the template context variable value is. So any of  these things can use filters. Basically a rule of   thumb, if you see two curly brackets, so really  good chance that you'll be able to use just a   pipe and then some filter there. And yes, there's  a way to make custom filters as well. So if you   have if you have a need to see that, please let  me know in the comments. And here is the built in   filter reference. Right. So we have all sorts of  different values. Notice that you can add numbers   or even a string that represents a number. You  can add variables. So if you passed in a different   context variable and you wanted to combine them  together, you could do that. We can do stuff like   slashes or cap first. Cap first is probably a  really good one for let's say, for instance,   in here, we changed my text to being title,  right. And then back into our actual template,   we would change this to being title. And let's  let's just go ahead and bring it into an h3 tag.   We put title here, and then we use that filter cap  first. And we close off at age three. And all that   does is it ensures to us that that first text item  is capitalized. So if I said ABC this refreshed,   and there we go. Pretty cool. Now luckily, the  documentation gives us a lot of examples of using   this right so like when would I actually use value  of center? Right so if I wanted to use center,   I can honestly say I don't think I've ever used  this template tag. That's why the diamond There,   but let's go ahead and use center and try it  out. If I refresh, oops, we have two extra curly   brackets in there. Sorry about that center. It  actually doesn't render anything for us because   of how templates work. But you know, so I mean,  the HTML, I think does have extra spacing. No,   it doesn't do anything. So it didn't do anything.  But what you can do is you can absolutely use two   things at once. So I can say cat first, right,  so I can filter then to cat first, like it does.   But then maybe we use the upper case, with just  upper. So slash upper. And all that's going to do   is capitalize the first letter and then uppercase,  all the other ones, right, so we can stack those   filters together, which is kind of nice. Now, I'm  not sure exactly when you're going to be stacking   these together like this, but it is possible.  Another thing that's possible is something called   safe. So when you pass in HTML, as a context  variable, let's say my HTML, and we said,   Hello, world, by default, when this is rendered,  right, so I want to render out some HTML in there,   when it's rendered, it is rendered as just plain  text, right? So it doesn't actually render the   HTML document. Right, so we can actually use a  filter in here called safe. So we can save that.   And there you go, it actually renders that HTML.  And there's a lot more like truncate characters,   right? Or title look at Hey, that's pretty cool.  So how about we do that we've got cat first and   then title. So title, and title, a title, a title  izes, the entire title variable, right, so this is   the variable, whatever that is, is the variable.  And then once you put those pipes there, it turns   into the filter name that it might be cool. So we  can do time until so using dates, stuff that's a   little bit more advanced than where we're at. You  can change the time, you can change the format of   time, you can strip HTML tags. Alright, so we see  here, we've got strip tags, before it's safe. If   I did strip tags, save them refreshed, hey, there  you go. It's no longer showing what that HTML is.   So those are kind of the reverse of each other  one actually renders it, the other one just gets   rid of it. These are pretty cool, very useful  inside of templates themselves. slug of I, hey,   that's another really cool one slug five, what a  slug. If I do, while we refresh in here, it turns   hello world with the h1 tags in there still into  a slug version of it, or like a URL safe version.   But I can also do strip tags, and then slug fi.  And hey, what do you know, it removed all those   HTML tags and Slug a fight it at the same time.  So you're gonna want to go to the documentation   for this, whenever you think like, hey, I need to  do X, Y, or Z. Because they're very specific to   generally what you're using. Right. So if you have  user generated content, and you want their title,   show up as a title, then you might do that. But  honestly, you might leave it as is you might not   enforce those things. And that's something that's  really cool about these template tags is you get   to pick and choose on when you want to use them,  I don't actually think that you'll end up using   them that much, honestly, because as we see here,  I'm showing you that they exist. But oftentimes,   when you have values like this, you'll do that  in the view. Or if you have something like this   also would do that in the view. And in fact,  safe should itself be done in the view with   something called Mark safe. But that's actually  not something we're going to cover just yet.   That's a bit a little bit more advanced,  but it's something worth noting. Okay,   so that's it for Django is built in template tags,  and filters. Now, we're definitely ready to start   rendering content from our back end. So the data  that actually has been stored in our database.   Now it's time to actually render data from our  database. But before we do that, we have to just   play around in the shell a little bit. So we  can understand how to actually access that data   in the first place before we render it out. So  to access it, let's go ahead and jump into our   terminal. And I'm in the root of my Django project  where manage.py is, I do have my server running,   but you don't necessarily have to do that. Let's  go ahead and jump into Python managed up UI shell.   Also, I'm assuming that you have this exact model,  our product model, you can add any model you want,   but make sure you have one model. And I'm going  to go ahead and import that from product stump   models. Import product. Okay, so if you're  not familiar with how these imports work,   might want to go back a little bit, but basically  we're going from that app. Look into that model,   module model module. That's a mouthful. And then  we're importing product. And to get any single   product item, we can do product that objects that  get. And then we want to use an id like argument   here. So ID equals one, I hit Enter, and I get  back whatever that object is. Now I can set this   to a variable itself. So let's say OBJ equals  to that. And then in here, I could do something   like dir OBJ, to see all of the different things  I can actually hit on this, right. So there are,   there are other intuitive ways on how to do  this. But this is maybe a natural way, if you're   familiar with Python, you would just use dir to  see all of the methods that you might have on here   or attributes that you might have on here. One of  them is ID, one of them is price, title summary,   right? So a lot of these are unique to my model.  And of course, that data is also coming from here,   but and a lot of built in things that Django has  itself in models dot model. So realistically,   you'd probably do OBJ dot title, or something  along those lines, right? So OBJ dot title is   unique to this model. And it allows me to grab  the title that I've saved in the database. So   now we sort of understand a little bit more  on how to actually grab some data. Hopefully,   you're wondering where the heck did Id come from,  and this get called, we'll explain that in a   little bit. But let's go ahead and exit out of the  shelf for now. And let's go ahead and create our   first view where we're rendering out this actual  data. So whatever this data is, so I'm open up my   views inside of the product app again. And I mean,  the reason I'm moving it out of the view of this   other one, if you've been following along, has  to do with congruency, right, so you want to make   sure that everything related to your products is  inside of your product app. So if you're rendering   out a view that's related to one product, that  should probably be in your product app. There   are a few exceptions to that. But just keep that  in mind. So all I'm going to do here is say, def,   and I'll just call this product. Detail View.  Without getting into too much explanation,   just stay with the naming conventions that I  have. So like product underscore detail view,   we're going to show one product. That's why we're  calling it a detail view. And I'll go ahead and   put in the request here. And then it returns  render, and it takes request some template name,   and then some context. So of course, we have to  create our template itself. So let's go ahead and   write product slash detail dot html. Right. So I  did add a slash. Now if you've been following me,   you haven't seen that yet. So we're going to talk  about that in just a moment. And the next thing   is the the actual context here. So I'm going to  go ahead and do from dot models doing a relative   import here. So from dot models import the product  class. And this is where sometimes people get a   little bit off. First of all, they might name  a function like a class. So don't uppercase   functions, keep them lowercase. Secondly, you  might put something like product here, that's   not a good idea. Just make sure that it's explicit  to what it is. So we're looking at a detail of a   product. That's why you want to put the product  view there. So just like in the shell, we did   product dot objects, dot get ID equals to one.  Now, there's a really good chance that this was an   error for you. And I'll explain why we jump into  the admin. So let's go into our admin here. And   we go into products, I actually have two products  in here, right, you might have a lot more, or you   might have zero, but my model actually has some  items in here. So if I click on this first one,   I see there's a number right up here. That is  actually the ID. We can also look at the other   product. That's the other ID, one, two. But if we  look at our model, there is no ID here. Well, that   has to do with Django has built in features. One  of them is that it has an auto incrementing ID,   which you can see in the migrations in the initial  file, we see there's this ID of auto field,   so it automatically creates that for us. We don't  have to do anything, another win for Django. Okay,   so how do we actually create the context here,  right, so it context is just an empty dictionary   by default. And what context do I want to put  in here? Well, I can put stuff like title,   and again, that was OBJ dot title. I can put  stuff like description, and OBJ dot description,   right? You could, you could fill out the rest  on whatever you want to show up on the model.   This context again, goes into my template, but I  actually have to create that template. So without   getting too too advanced level stuff of where we  can locate or load our templates, which I'll talk   about literally in the next one. We're going to  make a new folder. In this template folder here,   called product. And inside of that folder, we're  gonna make a new file called detail dot html.   That's all you have to do. So if you want to  have directories inside of your templates, you   just make a directory in there and make sure you  add that slash, put it the same slash as that way,   regardless of what system you're on. It should  still work. Okay, cool. So we've got detailed   that HTML. And with detail, we want to extend  so extends base dot html. Of course, this is   continuing from previous videos. So make sure you  watch those. And we do block content. And we do   just in block, there we go. That standard, we've  created our template, let's go ahead and make sure   we import our view to our URLs. So in our URLs,  we're going to go ahead and import the product   view. So we'll do from products dot views, import  product, detail view, that's the name of the view,   of course. And then finally, I'm just going to go  ahead and make a new path here. And we'll call it   product. And it just takes in product detail view.  Cool. And I'm just gonna go ahead and do an h1   here and say, item. Okay, so let's go back into  our project, go into product. Cool. If you don't   have this, stop, go check the code against GitHub,  do all that I just breezed through a lot of   things, because we've already done this. But what  we haven't done is seen how to actually render out   some objects data. So like some database objects  data, in this case, I actually already did it.   So you might already intuitively know, hey, I can  just do curly brackets title here. And then I can   do you know, something like p tag, description  here. And so on. Okay, save it, refresh in here,   got a new product looks like I don't have a  description. So I don't need to worry about that.   But of course, this is a good opportunity to use  a condition, we could say, if description, then   we'll just render out the description. Otherwise,  we'll say coming soon. Or rather, probably say   something like description coming soon. And  the real perfect. So again, if description   is not none, I mean, you could do all sorts of  like conditions in here that work in Python as   well. So those are Python conditions. Or sorry,  is not equal like that. In this case, it's not   actually equal to none. So we would want to say  and description is not equal to an empty string,   which it very well could be. And that's what it  was. Cool, a little bit more about conditions.   That's something that's great about watching these  tutorials, and building something real. Okay,   so now that we've got that we've actually rendered  out our template, we've rented out an object. But   there is one thing that's really disadvantage,  a disadvantageous to this method. So if we look   back into our view, what I have to do is I have  to map my objects context, right. So every thing   that's in my objects, meaning every field here, I  would have to map it to the context itself. That's   okay. But it adds an extra step like, meaning  if I ever changed my model, or I want to have   new data in my HTML, I also have to go to my view,  and that's a little inefficient. So what we want   to do instead is instead of all this, just get  rid of that, or let's just comment it out. I'll   leave it in there for for reference for you guys.  So we do content, and we say, object is OBJ. So   that now the context object is object, right? So  the context variable is object. So inside of our   detail here, we could then just do object ID,  title, object description, object description,   object description. Yes, I will promise that  I won't repeat that again. And then object   dot price, right. So now I can actually change my  template whenever I want and not really worry too   much about this detail view. Right? Oh, we got  we got an error. What happened? object a title.   That's not the name. It is title. So object should  be in there should have rendered, but perhaps we   didn't save our view. We didn't. Okay, cool.  So this is now rendering that stuff out. All   from the database, really cool. And of course,  you can play around change things, do all that.   You remember call that when I say To create a  Django app, when you do that, you want to keep   as much about that app inside of that app or that  components directory, right? When you do this,   you make things nice and simple. So you can use  that app in other projects. That's often the goal.   I mean, if you make a really, really good blog  app, for example, you can reuse that over and over   again, or even release it as a third party package  that other people can use as well. So if you end   up doing that, then that means that you're gonna  have to do additional configuration for it. Now,   this gives us a really good opportunity to talk  about templates in that context. So I've purposely   left this out, because I wanted to show you how  to render out some data about that app first,   and then move the templates around. Now, inside of  our apps, we can actually put a new folder in here   called templates. So inside of the sub app, you  can have a new folder in here called templates.   And you can do things inside of that, we can make  a new, another new folder and there, that new   folder is going to be the name of our app. So just  like in this templates, we did products detail,   we would do that same thing here. And in fact,  we would name it exactly like our app. And in my   case, I did product first. So I'm going to name it  two products. And then we will call this product   underscore detail dot html. So we've changed a  couple things about our template, I will copy   and paste that entire template itself, bring that  in, because we will see some difference. So I'm   going to just call this one in app template  with that title there. All of this is for is   illustrating the difference and understanding  how Django looks up templates themselves. So we   save this, and in our view, I'm going to change  this to products detail, not the exact thing,   because I want to show you something, you can jump  ahead and go to the exact same, but I want to show   you something. So if I save, then what's gonna  happen is I render this page out, and I get an   error saying template does not exist. So this is  actually pretty important to understand, because a   lot of times you put templates to the wrong place,  or you have a spelling error, or something like   that. This allows me to see what's going on. And  we've got this temper, template loader is showing   me how it's actually loading my templates. So  the first thing that it looks for is the file   system loader. This right here, believe it or not,  comes from one of our settings. So if we go into   that main configuration settings, and where we  actually set up this template, ders, that's what   that is. That's all that is. So if I had actually  written out the path to that, that would show up.   So if you were on the wrong system, you would see  the wrong path here, right. Thus, we make it like   this. The next thing is you'll see a few other  places where it's looking. It's looking in Django,   site packages, contract, admin templates, product  detail, it's looking inside of the Admin app   that's built into Django. And then finally, it  makes its way down to the actual app loader. So it   looks inside of our own app, inside of products,  templates, products detail. Of course, that's not   the actual name, the name that we change it to  was product underscore detail. So if I save that,   and refresh, everything looks good. But let's keep  it as product detail for just a moment. And just   uncover how cool this actually is. So we're going  to actually look at the Jango package itself,   inside of our project. Now do keep in mind  that we do not want to change anything in here,   we're just looking at it for illustration purposes  only. So we go into lib, Python 3.6 site packages,   Django, the just the single Django not  anything else. And then what I mean,   if we retrace back what's going on, we see contrib  admin templates. So contrib admin templates. And   here are other templates. Actually, let's look  at this Admin app itself. This is actually not   a whole lot different than what we have. There's  certainly more things there than what we have,   because we're still doing a lot of basic stuff.  But I mean, at some point, you might not ever have   an app with this much stuff. So that's not really  the point. The point here is, it's the exact same   thing. It's the same Django app with the admin  or the built in app as it is with what we're   doing. That's pretty cool. So you can actually  see the templates, and you could edit them here,   but you don't need to. In fact, what you would  do is if you want to override any of your built   in templates, or any of the app templates,  if you want to override something like this,   you would then just put them in your file system  once you would put them In here, with the exact   same path. So let's go ahead and change the view  back to being the actual proper one. So it's   products, right product detail. That's the end  all be all that we want. So we see that it says   inap template. Now, if I wanted to override this  template, or any templates for any of these apps,   I would come in to my template folder, that main  directory that I created. And I would rename   or add the same path that I had before. So I'm  gonna rename this to product detail. Okay, so now   it completely changed that refresh in here. And  there we go. So it's actually showing me the Oji   template, right. And that's how you go about doing  this. But do keep in mind that when you're working   on your own solo app, or you have a team, chances  are really good that you're going to want to keep   it inside of this itself. So I'm actually going  to completely delete this folder, I don't actually   want you to get confused about it. That's why it's  gone. But I just wanted to illustrate the purpose   of how all of that would work with your templates,  and how you would load them. And I think it's   critical to see it inside of map versus in any  other form. Because really, everything about this   product app at this point is inside of this,  with the one exception of the URL of actually   bringing it into the Django project itself. But  that's not any different for any of our apps,   including the built in one like the Admin app,  if I got rid of this, that app is no longer   accessible to Django. I mean, it's still working,  but it's no longer accessible to our main project.   So that means that it's a very reusable app. And  that's the theme here, we want to keep that up.   You see, we want to actually be able to allow  our users to save data in the database. And   they really wouldn't use the admin or the Python  shell to do that. So this one, we're going to be   breaking down the basics of using Django model  forms. So what does that mean? let's actually   take a look. Now, inside of any given app, I'm  going to go ahead and make a new file here and   call it forms.py. Do keep in mind that this works  for any model, not just the one we're using.   So we're going to go ahead and do from Django  import forms. And they will do from dot models,   we're going to import our model, which in my  case, it's product, right. And then I'm gonna   make a new class in here. And I'm gonna call this  class product model form. Or really, I would call   it product form, or product create form. Those are  a few different names that you might end up using.   So we'll just leave it in as product form. And  we'll call it forms dot model form. And all we   have to do here is do class meta model equaling  to product and then the fields, like the actual   model fields that I want to have in here, like,  you know, which ones of these do I want? Well,   let's just do title, and description and price.  Okay, so title, and then description. And then   price. Okay, so we now have our model form, all I  have to do is render this out in a view. So let's   go into a view. And let's import this. So from dot  forms, import product form. And I'm gonna make a   new view specifically for this. And I'll just  copy this detail view real quick. And we'll call   this product create view. I won't worry about the  object itself, right. So the context that I want,   though, is I'll just say form equals to product  form. And then we'll just initialize it with   request that post or none. That's a worry if you  don't understand what's going on here. In a few   videos, or the next few videos, we are going to  go into a lot more depth here. So just just bear   with me. So if form.is valid, that's another thing  that we will end up doing. I'll just do form dot   save. Okay. And I'll go ahead and add in this form  here into my context. And I'm gonna make a new one   called product create dot html. So that means I  need to make that template itself. And By now,   you should absolutely know how to do all of this,  right. And a simple way to do it is just copying,   of course, our other template. And then in here,  I need to create a form element or a form HTML   element. And I'm also going to do input type  equals to submit. And we'll say value equals to   save and close that off. And then inside of that,  we'll just do form dot As P. So this is a built in   method that turns the form that we're passing as  context into a actual HTML form rendered out with   paragraph tags. We'll take a look at that code in  just a moment. But now that we've got this create   view, let's actually bring it into our URLs. So  into the URLs, import this in. And I'll just go   ahead and make a new path for it. I'll just call  it create. And it's going to be the product create   view. Okay. So again, let's make sure everything  saved, all across the board, forms, templates,   all that stuff. Let's go ahead and look in to  this create. And here we go. We've got our form   rendered out here with the actual fields that  we specified. So I'll just say new product,   this is awesome. And some price, right doesn't  really matter. I hit save. And I get some error   here, right? So I've got this stuff up here,  it's not really an error, it's just I didn't   actually specify the method that I'm using  on the form itself. So back in my template,   we'll go ahead and say form method equals to post.  And we're also going to add in this CSRF token,   okay, these things we will absolutely discuss,  when we break this down and go from bare minimum,   I just wanted to show you how to do it first.  Hopefully, to pique your interest to learn a   lot more about this. That's the point. Okay, so I  refresh in here, let's get rid of all that stuff   in the URL. And I'll just do a new product again.  And description does it matter? Price 1299. Okay,   so I've got this not null constraint failed,  right? So I have an error here. And that's   because if we look at our model, take a look,  we have this featured, and it's required,   and it's not blank. That's where this error  happens. This error happens all the time,   which is part of the reason I actually left it  there. So to actually overcome this, for now,   what I'm gonna do is just add in a default  of true, or a default to false, either way,   that part doesn't matter. But we made some changes  to our models. So what do we do Python manage.py,   make migrations. Oops, we want to make sure we're  the root of our project where Python managed up py   is making migrations and Python managed up, py  migrate, okay? Let's try that again. And we'll   say new product, or new course, whatever, doesn't  actually matter. Like I said, a million times,   I go ahead and save that. And I can't tell if  it actually anything changed. So let's go into   our admin. Let's just log in there, go into our  products. And what do you know, it looks like I   have more products. So I've got new course here.  And then new course here. So I actually saved a   few different items of data. So one way to solve  that problem is in clear out what's in there, it's   really simple, we just go back into our view, and  we re render it just like that. So we would just   rerender the form. So then the context will change  and update for us. So let's go ahead and we can   literally reef, submit that same data, we get this  error, that's a security problem or not a security   problem, but a security feature. So let's go ahead  and just add in another one. And some price we hit   Save clears out the forum for us, we go into the  back end. And we know we've got our product there.   Cool. So we now have a model forum. So the next  few videos, what we're going to do is really just   break this down a lot more in depth, like how do  I actually build a HTML form from scratch, and   understand that data, that's where we'll start.  And then we'll get more and more complicated to   better understand how forms work in general, and  then better understand how they work with Django.   Because this is certainly not the only way to  do it. But it's a fairly easy way. Even if it's   doesn't feel like it's that easy of a way, I  promise, this is a fairly easy way to do it.   Now that we've created this product model form  and rendered it out inside of our product create,   it's time to just take a few steps back  and do it from scratch as in raw HTML,   and then move up the chain. So one of the first  things that I'm going to do is actually get rid   of the Django related stuff. So those two things  are now gone. Right? So we have only one HTML   input here. And that is to save it. So the first  input that I want to actually put in here is input   type equals to text. And the name is going to be  titled as in what do we want to call this input,   I'm given the input itself is a name. So I can use  title, I can say, my title, neither one of those   actually makes a huge difference, which we'll see  why in a moment. So we got input type, text, name,   title. And we can also add in something called  a placeholder, where we can just say your title.   This is just kind of giving them some information,  we'll see what that is in just a minute. Okay,   next thing is in the view itself, I'm going to go  ahead and comment this one out, and create a brand   new one that only renders out empty context. And  no form related data. Okay? So we've really read   Bree, you know, backed up a lot, and redid this  view. Okay, so we look at this. And we look at   that view, let's go ahead and take a look at it  inside of create. And we've got your title here   with a Save button. If I type out ABC and hit  save, I get this CSRF. verified, failed. Okay.   Now, why is that happening? Well, it actually has  to do with our method here. So if I change that   method to get what happens, I refresh and say ABC,  it save, it seems like something happened. But   what you might have noticed is the URL changed,  you see get methods are what is the default method   for a form. So if I just typed out a form like  this, and rendered it and said something else,   it will change the URL. This is actually very  similar to like when you want to do a search on   your website. But instead of doing a search, and,  you know, going into the nitty gritty of that,   what we are going to do is keep that method of  post. Okay, so we save that and then refresh,   try ABC again. And we get this forbidden yet  again. Now, this has to do with security measures   that Django has built in. Now, a big part of the  reason for this is something called action. So if   we type out action, and we set it to, let's say,  a different URL, let's do like slash search. And   let's go ahead and bring that method of get back.  And I type in, let's do a refresh in here and type   in ABC, hit save, whoa, what happens, it takes  me to a different URL, as well as a different,   you know, also including that data that I actually  put in. So action then means that you can send it   to a completely different URL. So what if I  did the same thing with like Google, so WW,   google.com, slash search, I'm actually going to  get rid of that trailing slash there. And I'm   also going to change the name here to Q. And then  I will just say your search, we save that. And we   refresh in here, we've got your search, and I'll  do Django CFE, hit save, hey, what do you know,   I actually performed a Google search right  there. And what's pretty cool is clean,   fresh produce came up a lot. That's awesome. I  like seeing that. Okay. But what's more important   here is understanding that, hey, I just created  my own Google search form, which is really nice   for one feature. But the other part is, none of  this in here is related to Django. So you actually   learned a couple things. Number one, the action  will send the form to whatever URL you put there.   Now, if we actually changed this method to post,  just like that, and now searched the Django CFE,   let's just refresh in here. And now search  that hit save, we get a four or five error, the   request method post is inappropriate for this URL.  Now, that hopefully makes sense. If it doesn't,   I'll explain in just a second. But it's pretty  cool, we can actually change the action and we can   change the method. Now by default, what happens is  the action goes to the current URL. So if you do   period here, you can see it as an empty string or  period. Either way, it's going to go to what this   URL is pretty nice. And then it's going to use  that POST method. So again, we're going to change   this back to being title and your title. And then  we save that and do ABC, I hit save. And again,   I get that forbidden call once again. So to  override that problem, we do see s RF token. Okay,   so we save that and we refresh in here. Confirm  for resubmission we can say yes. Let's try it   again. And there we go. So it actually goes away.  So the data seems to be going through. Now what   the heck is get in post Now get request is meaning  that you go to any URL. So when I go to any, any   URL on my page, like about contact, whatever you  are getting information from that, when you want   to save information in the back end, we use post,  like kind of like mailing a letter to somebody,   you post it right? This is very similar. And we  just use two different types of requests to do   that. Now, what's happening is actually not a  whole lot different, like the backend can treat   both kinds of data in the same way, which we can  see in our actual view itself. So our view itself   has those two methods built in. So if we do print,  request dot get, and print request dot post,   we can actually see what's going on with either  one. So with get if I just refresh the page here,   I see that I've got this query dictionary that's  empty. And what I can actually do is say, you   know, title equals to something, right? So I've  got now I have changed my GET request, because   I changed my URL, I can now see in here that I've  got some data coming through from there. So this   is an actual dictionary that I could say get  dot get or, you know, grabbing the actual item,   key value pair there. And that will print out  whatever Title I put in here. So if I said, Yeah,   this is a title, it's going to actually print that  out for me in the backend. Pretty cool. So yes,   you can absolutely save this data, I don't  recommend doing that using Git is a unsafe   method for saving data. That is why there's a  security feature for post. And that's not unique   to Django. It's certainly not unique to any web  application, it's it's a general rule of thumb,   to when you have posts, you want to add in  some security. Now, the reason why is that,   if I was going to have this title in my URL, then  a hacker or somebody else can just use a link,   that changes it to being something like this. And  that would quite literally change the title for   me, it starts to bring up all sorts of security  questions that you may have. So instead of doing   that, we use request post, right, so I'm gonna get  rid of this part of the get call. And then inside   of my form, I still have an add post. So I can get  rid of all that and do ABC, hit save. And now what   I see is all of that data coming through. Pretty  cool. So that means they'll the very last part   of this is I can actually come in here and say  title equals to request dot post that get title.   And I'm using di get for the dictionary itself  to grab what's in there. And that's going to be   the title I would use. And then I'm actually not  going to save it because I don't want to put all   of the information in. But if I did product that  objects that create title equals to my new title,   right, so my new title. And then I had every  other field in there, I could then go about   actually saving that requested post data, which  is denoted by just printing out that data itself,   right. And getting rid of these requests methods  here. Okay, so let's save ABC and save. Then there   we go. We've got our title being printed out.  Let's go ahead and save it again. And try it   one more time, not refresh. ABC, we hit submit,  and all I see is ABC. At the very first I see   none. Now why is it that I see none at the very  first is because we don't have any post data by   default. So there's a lot of things that I still  need to dive into when it comes to this. But what   I just showed you is how you would write a raw  HTML form in Django. And then just generally   how you would create the data from that, there's  one thing that you could do is say is if request   dot method equals equals to post, then you can run  through and do all of that stuff. And that's okay.   So that's asking for the method, whatever that  method is, will give you, you know, get post or   a few of the other HTML methods. And then you  could go ahead and save it. And then that way,   when you refresh on that page, it won't say none  first, like it did, right. Instead, it will just   only render out ABC. So it's not an error because  I copied and paste it but let's just hit enter   a lot and just illustrate the point. I refresh  that page. I got my GET requests there, I do ABC   hit save, I got my post request, and the actual  post data. Cool. So if this is unclear at all,   you might want to look into more about HTML forms  themselves, please let me know in the comments.   But this is really a bad method of saving data  is it's really, really poor, because we're not   validating if this is good data at all. We're not  cleaning this data. So we want to make sure that   we do that. And that's another topic that we need  to discuss. And we'll do that in the next one.   So I'm actually going to again, comment  all of this out, copy it and paste it over,   probably should have copied it first.  But you know, whatever. Okay, so again,   I'm going to go ahead and delete all this, because  we're basically starting from zero, or as if   we were starting from zero. Okay, so I've got my  view here. And then I want to open up forms again,   just go ahead and ignore this for now. But it is  not a bad reference. So I'll just go ahead and   say class raw product form. And it takes in forms  dot form. So it's not model form, just a standard   Django form. So with the standard Django form,  we have to declare our inputs. So in my case,   I've just been using model but I can go further  than that. And we use forms dot char field. And,   you know, we can say description. And we'll also  do forms dot char field as well. And then we will   say price, and forms dot decimal field. So these  should look very similar to our models. And that's   because they are, so we've got our decimal field,  char field and our we don't actually have text   fields. So if you try to do text field, it's not  gonna work. I'll discuss that later. But we'll   just do char field. And honestly, if you wanted  some reference for that, you just do Django form   fields. And it should give you the field types in  here. Right, so form fields, all of the various   field types are in here. So you can absolutely  use any of those. But, you know, text field is   not there. So these all render out a specific look  by default. So if I grab this form, bring it back   into my view, and bring it into my new view, not  back into it, we had the render of this for. So   to render it out, we create an instance of the  form. So we'll say form is that this creates an   instance of that form, as you may be familiar with  Python, and how you create instances from a class,   we add that form into our context. Okay, so again,  we could say my form here, and then have form   they're still going off that product creates. So  back in that HTML, I'm gonna get rid of this here,   and just do form.as P. So this renders it out  as paragraph tags. So if we save this, and take   a look there, let's just refresh that page, I can  inspect the element and take a look and see that,   hey, we've got our form. We've got an action,  we have our CSRF middleware token, that security   token. We have some p tags in here. And that's  as P. There's other ones like as HTML, or no,   not as HTML, but as Li, or is it ul from like  that? met, there you go. So you can render it out   as ul is HTML. So as HTML doesn't make sense, but  as P is a way to render it out, and now we have a   form with some data. So I can add in whatever  I like, right? And hit Save. Now, naturally,   what just happened was, we submitted the data to  our form here, or at least it seemed like we did,   but we didn't, we didn't do anything. Right. So  this form itself is just rendering now, it's not   actually getting any of that data. And that's why  we use request dot post here. So if I save that,   just as is and refresh in here, let's just refresh  in this page. And I see that now. It's giving   me these validation errors. These are called  validation errors. This is awesome. This is built   into Django right away. It's already validating  stuff for me. Unlike the HTML, the HTML absolutely   was not. But it's asking, like, Why are validation  errors even happening happening at this point,   right? So we see that this field is required, but  how does Jango already know that? Well, it has to   do with what I initialize it with. So I have it  in as request post. So let's make this work. Using   kind of a long way at first, we'll say if request  dot method, equals equals to post. Alright,   so again, that's built into the request. object  itself that's been passed. So if the method is   equal to post, then that's going to be my form,  I'll actually use that data in my form. In other   words, I'll pass in that request, post data as I  initialize my form. So I also have to initialize   the form by default, so I need a get method for  it. And that's where this comes in, right? So I   render it for the get method. So I can see what it  looks like. And then with the POST method, which   is a different type of request, which means that  I still have to render it for that different type   of request. So we've got this is roughly requests  that get right. So that's what is passing in by   default. But requests I get doesn't have anything,  probably. So we'll go ahead and leave that out.   And now this will actually handle my form data. So  if I save this, and refresh in here and hit save,   it's now saying, please fill out this form. And  that is based off of my browser and see that it   says required there. So if I actually removed  that, right, so I literally removed it from the   code in the elements, you don't have to do this,  this is more illustration purpose, and hit save,   it just moves to the next one. So again, I  removed that. And then the final last one,   all those requirements, just remove it, and I  hit save. Django now does the validation for   me. Right. So I actually showed you a way that  a user could potentially disrupt some of your   raw HTML forms. And that's where Django security  comes in, not just for this, but also for this,   right. So I absolutely need all of those things  working. So I had all of those fields required.   And this is a way to actually validate it, this  does the validation. So there's a method called if   my form is valid, this will actually say, hey, you  have a valid form, you know, now the data is good.   And I'll explain the data part in just a second.  But now that the data is good, we'll go ahead and   print out my form dot cleaned data. So this would  be the data that actually comes through from the   form after it's been validated. Okay. And then  we could also say, print else my form dot errors.   Okay, so we've got those two different methods.  So if it's valid, then it's going to do that,   if it's not valid, then it's going to print out  what those errors are. Oftentimes, you won't   necessarily need this because the form itself, as  we've already seen, renders out the problems that   might be related to that form. And that's because  of this right here, too. So a lot of built in   features going on here, that we're just not quite  breaking down just yet. So let's go ahead and take   a look at this, let's actually put in some valid  data. So we come back in this create method,   I'll say ABC, you know, whatever. And whatever, I  hit save, and nothing that form doesn't rerender,   which will solve that problem in a minute.  But if we look at our terminal, we see, hey,   here's our clean data, it actually gives us that  data, and that error list digit show up, as well,   because we re submitted the form, and there were  some errors. Okay, so what is another thing that   we could do that, you know, would potentially  cause some problems? What if I change this price   field? What if I go to inspect element, change it  and change the type in the actual HTML to text?   Right, so now I can actually type out text type of  text type text, I hit save, hey, it's got to be a   number. So that's other built in validation that  our forms actually have. Right? So from this data,   let's actually save an object, let's actually  do something that you would end up doing, right,   we've got a product that objects that create, and  we have some of that data that's coming through,   right, we have a dictionary of this data.  And it's doing title, description and price,   right? I named those fields on our form. That way,  on purpose, it was to match our model. And that's   what you should do as well, because again, we're  working towards this model form. And we're doing   the long way we're understanding more as to what's  going on. Okay, so now that I've got that I've got   this create here, well, what if I actually just  passed in this data, so let's go ahead and pass   in the clean data here, just like that. So I'm  gonna create it from that clean data. So let's   go back in here, and I'll say, new title, some  description. You know, some price, I hit save.   And again, I get an error here, right? So what  we can do is actually use the two stars here,   and that will turn this into arguments that we're  going to pass. So let's try it again. I hit save,   no errors. Let's look into my back end.  And I've got a bunch of new products with   that exact same name. Cool. So I actually was  able to save some data from my raw Django form   that does some validation for me. Now there are  parameters and things that we can set in here,   there's definitely a lot more that we can do  with these fields, including rendering out how   this description works. So we're going to dive  a little bit more into that in the next one.   Now, what we're going to do is things related  to any individual field, like let's say,   for instance, you want a field to not be required,  or you want to change the label of it, or whatever   input is in there by default. So if you take a  look at your forms themselves, we can change a lot   of things very simply, do you want this field to  be required? Well just type out required True or   false? Right? Obviously, with the title, I want it  to be required. And that's actually the default.   So really, you don't have to write out whether  or not the default is true, you would just say,   false. Now, of course, you might be wondering,  how do I know where the defaults are, of course,   the descriptions on the documentation for the  core field arguments will tell you what the   defaults are, like required, the default is true,  it's in here somewhere. The next one is changing   your label. So if you want the label to not  even appear, just make it an empty string, it's   a very simple way to do it. And like something  like price, you can also set an initial value.   So initial equaling to, let's say, for instance,  199 99. Okay, so that's a simple and easy way to   change those three initial arguments to any given  one of those fields. If I refresh in here, there   we go. It actually shows us for that. So more,  more specifically, not necessarily refreshing, but   just going back and re rendering the page, this  number is actually in here. So there's absolutely   more things that we can do in here as well. Like  notice that I don't have any placeholders. Well,   and also the description itself is not rendered  out as a text area. So let's do the description   first. And we'll change this to being a text area  by overriding the default widget by putting widget   equals to forms dot text area. And that's it,  I refresh, and there, it gives me a text area,   you can look up all the various widgets  also on the documentation for the forms,   because there's definitely a lot in there. And you  might end up changing things like a text area. And   perhaps you want to have even bigger or larger  changes to that that particular input. And we   then just put in some parentheses here, attributes  equals to another dictionary. So since I'm really   overriding a lot of this, I'm just going to go  ahead and separate out some of this. So I can   more clearly understand what's going on here.  First attribute that I might have is class,   like maybe you want to set a new class name  here, new class name, or multiple classes, right,   too. You can also set the rows that you'd have  on here. So let's say we did 100 rows, I refresh,   hey, that is a big form there, right? Of course,  that's probably not likely, maybe you do something   more like 20 and have a bigger text area. And of  course, you could do columns as well. Okay. And   of course, if I inspect this element here, I see  that, hey, I've got the name here, I have the two   classes that I added. And then I have an ID, what  if I change the ID in here? My dash ID for text   area. Refresh in here, need to make sure I put  a comma at the end of that said is a dictionary,   I now see them ID has changed. So any different  attributes that you want to put on there,   you absolutely can. And that's a very easy way  to do it. Now, you could also do it on the title   tag. So we wanted to say that we want to put a  placeholder here. So let's go ahead and do forms   dot txt input. This is the default widget for the  char field. So we would just change that to being   attributes equals to placeholder and whatever  you want the placeholder be so your title, say   that and we refresh in here. What do you know your  title is showing up? Of course, that placeholder,   you might also want to have that inside of your  text area, so your description, and so on. Right.   So that is how you override some of the basic  things about the form itself. This also changes   how the validation works just slightly, at least  for the required, right. So if I try to save it,   and I type out some of the other ones, the  descriptions no longer required. So it's no longer   going to show up with the price and the title are  required. So if I get rid of the price, it will   tell me to fill out this fill field itself. And  that, of course, is the web browser doing that.   So if I did that little hacky thing where I got  rid of the required element on here, and hit save   again, it gives me that same validation. So that's  pretty cool. But it's only giving us a little hint   of what validation actually is. So this part is,  well, we're actually pretty much identical to this   product form at this point, the forms themselves  aren't any different in the sense that the model   form renders out the same sort of stuff. And here,  the only difference is how the view handles it.   That's it, you might remember, we just did the  form itself. And then we just saved that data,   this is actually doing roughly that same  thing. So now going forward, we can render   out new types of validation for our forms. So  let's go ahead and do that in the next one.   Django has a lot of built in validation for its  fields. So when we render out a Django field or   Django form, we actually can submit some data,  and Django will check to make sure that data   matches that built in validation. So if we take  a look at the model form, which is now what we're   going to use, I'm going to show you that it's  really simple to override the field themselves,   right. So if I actually bring this title in  over here, I see that this is the same name as   that one. So that's actually how you override what  comes in by default. Kind of a cool little feature   to have. So now what hopefully you realized, and  I did mention in the last one, but now these forms   are actually identical, they have the same three  fields, the only thing that's different is how the   view handles them. That's it. But we're going to  go back to using that product form itself. So I'm   going to go ahead and comment out all of this. And  we'll come back into our original product create   view that we were using. Okay. So what I have  here is a shortcut method to what I did up here,   right, so that request post, and then render these  things out. All this does is renders out that form   if post data comes through, otherwise, we'll just  render out an empty form. That's all that's going   on that right there. Okay, cool. So now that I  understand that, what I want to do is just take a   look further with this is valid related stuff. So  let's go ahead and take a look, make sure my form   is coming through, I refresh in here. And I've got  my price my field is required. So it's possible   that I might need to save a few things here. Let's  make sure everything's saved up. We've got our   forms, and we go, and we refresh, our title goes  away. And if I go back on the Create, it shows me   that I have my placeholder there. So yes, I can  absolutely just copy all of these things in here   as well. And once I do that, I have a more robust  form, in the sense of how I want it to look,   and almost how I want it to work. So so when you  do this, you realize that you did change quite   a bit. And yeah, there's absolutely shortcuts to  doing this. There's third party packages that do a   lot of this stuff for us, which we're not going to  talk about yet, because it's getting a little bit   too advanced. But instead what I'm gonna talk  about is like, what if I want my title to be,   you know, to contain a certain word, let's say I  wanted my title to contain CF E. Right? So that   word itself or that those initials itself, what  I need to do here is come in and say define clean   underscore, then my field name. So whatever field  that I'm going to be grabbing the validation for,   this is what I want to do. Clean title,  right so I want to make sure my title has   a specific item in there. So he's just say  self and we can do ours and keyword ours,   those are probably not necessary. But oftentimes  if you're not sure, when you override something,   just make sure you put RS and keyword ours. So  to get the actual title itself, we do self dot   cleaned data dot get title. Okay, so this is going  to get The default title, this is going to get   the post Django form cleaning. So Django will  clean the form itself initially. And then it's   going to trigger this title. In other words,  this is not overriding required, for example,   that required will absolutely still be in there.  And to validate this, we just are going to go   ahead and say if title or rather if CFE in title,  then we'll return. Well, do we want to do it this   way? Right. So let's, let's just do the logic  first. So if CFP is in the title, then we'll   return that title, who whatever that default is,  otherwise, we'll do forms.or rather res forms that   validation error. This is not a valid title. Okay,  so we save that. And let's take a look refreshing   here, I'll say ABC, hit submit, hey, this is not a  valid title, there is our validation. It's really,   really simple. I mean, it's not that advanced or  that complex. Of course, I actually wouldn't write   it in this format, what I would do instead  is say, if not in that title, then res,   the validation. And the default, returning that  title. Now the reason for this is, so I can have   multiple validations, if I wanted to, if news  is not in the title, not a valid title. Right.   So ABC space, we get to not invalid, well, let's  actually save and refresh this. Let's Let's do   that again. So as ABC, I hit save, I've got this  is not a valid title. Okay, so right off the bat,   it will raise that one. Now, assuming that I put  CFE in here, like that, and hit save. Again, it's   gonna say not about the title. So it would have  to validate all of these conditions that you might   have. And of course, these aren't realistic ones  for a title, this would probably be more realistic   for like an email. So let's say for instance, if I  did clean email, and we did email, I'll throw this   email and just second the actual field itself.  So let's just go ahead and say if not, or rather,   if email ends with the edu, or if not ends with  EU, then we'll do res forms dot validation error,   this is not a valid email, then we can return that  email. And since I'm doing this, this is a new   little feature that you might end up using is you  could say email equals two forms dot email, field.   Notice on the model form, it's certainly not on  the model. So I'm gonna refresh in here, I got   my email field in there, I say abc@gmail.com, I  hit save, not a valid email. So it's pretty cool.   validation is fairly simple. And then you can run,  you know, any sorts of validation things on here.   Now, I will say that doing validation is not only  on a form. But since we've been working in these   forums, it's a really good way to introduce  validation as a concept, you can absolutely   do validation on the fields for a model as well.  But the idea for validation works, whether it's a   model form, or just a standard Django form. And  what you should see, or hopefully, this pattern   that you're noticing is that if I commented this  out, and change this to a form, the form itself   will render the exact same, all of the validation  will render the same, all of that. But of course,   the one caveat is how the actual form would  work. In the view, it is slightly different.   So to set initial data on a form, all we have to  do here is create a dictionary, so like initial   data, set that equal to something. So what are we  setting an equal to, it's going to be the names of   the fields inside of the form. So looking at  the form, we have our raw product form here,   we would do title, description, price, any of  those things, we would set the initial data here,   so and of course is outside of the form itself,  because it might change based on your view. So   this is my awesome title, something like that. And  then we just pass it in to our form. So we just   say initial equals to that data. And again, we can  use any of the fields that are in there. So if I   refresh an air, what do you see, we've got that  initial title in there, it's not a placeholder,   it's literally the same text, or it's  the actual text that's in there. Now,   I don't know how often you're going to do this  in a raw Django form. More likely, what you'll   do is do it in a product form or a model form.  itself. So if I changed it to a model form,   the data is not any different, it still looks  exactly the same. And that's because model form   is not a whole lot different than a Django form.  So if I actually added one more attribute to this,   and that is actually changing an object that's in  the database. So to change an object, we want to   grab that object first. So product objects that  get will say, right now we'll say ID equals to   one. So we still have to look up dynamic ways of  getting these objects. We haven't talked about   that yet. But to actually change one with this  form, all we need to do is pass it in as instance,   equal to whatever that lookup is. So in this case,  it's just OBJ. So now what I can do is take a   look at that object. So I still have the initial  data there. Let's look at the price though. If I   refresh in here, I see that the price actually  changed. Although the initial title didn't.   Usually when you're editing something in the  back end, you're probably not going to have that   initial data come through. Instead, what you'll  have is the actual title itself. And of course,   the final step to make sure that you can edit  it is, first off doing is valid form is valid,   and then you can just do form not save. Okay, so  we refresh here, and I'll just say product instead   of product title, and I'll change the price to  some ridiculous price, I hit save, seems to be   working, we'll just double check in the admin  to make sure that it is we look at our products.   The very first one, because we were going off  of that very first one, we see product, and we   see that new price, it works. That's how you set  initial data as well as editing model form data.   Now we're going to change our content based off  of the URL, otherwise known as a dynamic URL.   So first of all, we're gonna say object equals to  product objects dot get ID equals to one, so we're   setting the default. So we can see just exactly  how this works. So object equals to OBJ. And then   we are going to render out this basic template  from this basic model. And then finally, in our   URL, this is what it looks like. But we want  to do is make it dynamic. That is I want to be   able to pass in an ID here. So if I put in one or  two, this content will actually change based off   of that. To do it, we just put in these brackets  here. And then we declare the type. So in my case,   I'm going to use an integer, you can also use str,  you can also use slug, and there's a few others   I'll reference in a moment. So integer, and then  I'm going to give it a name. In my case, I'll say   ID, you can also say my ID or pretty much anything  else that you'd like ID is default, right? So   that's sort of standard is using something like  ID, or if you were using a slug type, you would   do slug colon slug. But we're going to use it for  integer and just pass in that ID. What this does   is it passes in a new argument to our view. So our  view has the request by default. And it passes in   that new argument of ID, which we declared the  name of, again, if you change the name here,   like my ID, you'd have to change the name on your  argument right there. We'll leave it like that   just for illustration purposes. But what's going  to happen now is our object is going to change   based off of that ID, because we're going to pass  that variable in, just like that. So we save that   and I refresh in my page, I go to page one, I get  a dynamic view. I mean, I need to make sure that I   save everything here. But this is an error that if  I actually didn't update my view function, this is   what happens, right? So I'll save this, and I'll  re play that error in just a second. But if I   refresh in here, I now see that what do you know,  it's now a dynamic URL, and it's actually doing   the lookup based off of what's in the database.  So if we go into our products and click on any of   them, we see that it's also doing that same sort  of lookup. Granted, the URL is slightly different,   but the number is iterating. So again, if I  actually change this to ID, and refresh in here,   I get this problem, this dynamic lookup or view,  this is really just our view function here doesn't   know what this keyword argument is. So we  just have to make sure that we put it in here.   To handle a missing objects. From a dynamic  URL, we are going to import a new shortcut   called get object, or 404. So basically, it's  going to raise a 404 page if it's not used. So   all we need to do here is get object or four  for the actual model that we're using. And   then the lookup parameters that we're using. And  that will solve that error. So we save that and   now if I go in here on product does not exist. No  Longer will give me this sort of error. Instead,   it'll just say page not found this is a valid  error. There's one more way to do this. And   that is putting it inside of a try block.  Let's do that really quickly from Django dot   HTTP import http 404. This will also raise  that 404 page much like this get object or   four, four. So I'm going to go ahead and  comment this one out and do OBJ equals to   product dot objects. dot get ID equals to ID.  And again, I said I'm going to put it into a try   block here to handle the exception, so except  this product or the model name does not exist,   then we'll go ahead and raise the http 404.  Okay, so we save that refresh in here, again,   we get that four four error. And if I change it to  some other number still doing that, okay, cool. So   actually, let's look at this real quick to see  how I know that this is it other than the fact   that I've been doing this so long. So if I save  this, just like that, refresh, I get this, this   is an exception right there. That's an exception.  This is just a simple way to handle set exception,   this get object or four, four is the preferred  method, because it's a lot faster than writing   all of these different things out, or even just  the entire try block. So again, I'll just use that   deleting an object in the database is  super easy. All you just type out is   OBJ dot delete. And that will actually  delete that object. But unfortunately,   this will happen on a what's called a get request,  right? So we want to avoid that from happening,   we want to have it on a, well, let's say a  confirm post request. There are other requests,   there's something called a delete request, but  we're going to do it on a POST request to confirm   that they actually want to delete this. Okay, so  what that means is we are going to render out a   form in here that will just do the post request  for us. There's really no data in here. But all we   need to know is if they actually submit this form,  that means that they want to delete it. Otherwise,   they can go back a URL. And of course, I'm using  this URL pattern here, not a whole lot different   than what we've seen before. Okay, so to do this,  then we just are going to go ahead and say if   request dot method equals to post, then we'll  just go ahead and delete that object. So again,   this is a confirming, delete. That's it,  it's not actually the method to delete,   it's just confirming that they want to. So if I go  now on that URL for any given object, I hit say,   yes. And then if I actually refresh in here, I see  that it actually goes away. So the final thing on   here would be to sort of redirect them somewhere  else. And we could just do that with redirect.   shortcut, and just do return redirect. And we'll  just go back a few pages. Okay, or relatively,   we'll just say yes. And that will bring us  back to that. So we can do something like   that. And that brings back a couple more  times. And yes, this is actually deleting   these things in the database. So we delete it,  we say, yes, it brings me back to that product,   where I might list them out. But this, this is in  the database, we now see that those are all gone.   Kalista objects, we first have to get a query set.  And that is typically named as query sets query   set that objects that all that is a query set,  this is going to give us back a list of objects.   And a typical context variable name for a query  set is object list, just like that. So that means   in our variable, I can actually render out that  object list. And you should know now for OBJ,   or for instance, and object list. That is  my for loop inside of a object list. So I   can use the instance variable inside of that  for loop to get, you know, my product title,   something like this. So instance, that ID. And  we'll just put it into a p tag. There we go. Okay,   so save that, save the view, save your URLs,  and take a look. So if we go back into products,   now I see all of my data coming through the  query set renders as well, which obviously,   I don't want to have happen. But now I actually  have a list of items that I can see in this   template. Let me get rid of that object list.  But something you should notice is this right   here could be reused with any model. And that's  the purpose, right? We want to make sure that we   can make these things reusable, and that's why we  use standard names like query set and object list.   To create a link to the detail of any given  product, you might do something like this.   And of course, it would actually work, it would  take you to the relevant URL and path with those   dynamic URLs just fine. But the problem with this  is that if you ever changed any of these URLs,   let's say for instance, you change them all  to p, then you'd have to go back and make sure   that all of these things are changed, and it's  just a lot more cumbersome. So what we can do   is create something called a instance method  on our model or a function on our model that   will shortcut this for us. And it's called get  absolute URL. This is actually the convention   to grab the URL inside of Django, so it's  used in other places. But for right now,   we'll just go ahead and use it in ours. So  I can return the products. And whatever it   is that I'm using for the URLs, using the  F string or string substitution here allows   me to actually grab whatever that URL is based  off of the instance. So if I do change the URLs,   I can just make sure or know that everywhere they  get absolute URL works, this will update as well.   So we just do instance dot get absolute  URL. And that gives me that actual URL.   It's time to transition our get absolute URL  method to being dynamic itself as in this string   right here. So if you look at a URL, we actually  named our URLs on purpose. We haven't talked about   them yet, because it's only related to this  part. And then is making this being developed,   based off of whatever this is named. So to  do that, we use a function called reverse,   come in here and call reverse. Here are some of  the defaults that we use keyword ours, hopefully,   you're familiar with keyword ours in the sense  that, hey, these are keyword arguments that I'm   passing to my view. So I know that I need to pass  those as well. And what do I need to pass? Well,   Id and self.id. So self is referring to  the instance of the object, and then ID is   referring to the ID that's built into it. The  next thing is, I just need to call the name,   so the name of the actual URL that's going to  handle this data. And that is our product detail.   So that's the name just product detail. So we save  that and we go ahead and refresh in our links,   course, all of that is now working. So that's  a clean and easy way to make sure my URLs are   dynamic. And what I mean dynamic is in my  urls.pi, if I ever change this to let's say,   P, those links would actually update, right,  so if I click on that, it now actually updates   it as well. And it does it across the entire  site, everywhere where the get absolute URL   method is used, which there are third party  packages that use this as well. So let's just   keep that in mind when it comes to making  this more dynamic. Sure, you can hard code   it. But that is definitely not a recommended  method. So let's leave it as products slash   take everything we've done so far, and just clean  it up into their own views with names that match   to your app, you'll see something like this, the  Create view, the update view, I changed this,   the list view, the detail view change that, right,  so you should have an idea of how to do all this   if you don't go back a few videos. Now what we do  is we look at our URLs, and you'll see something   like this, this is related to that. But the  problem comes up in two forms. Number one,   we have this is not actually that reusable of an  app, right? I have to actually import all of these   views right on my URLs. And number two, what  if you accidentally use the same name and same   keyword arguments somewhere else? Remember, our  model is based off of that. What happens? Well,   what happens is, it doesn't work as expected, you  go to a different view altogether. That is not   great. So what we want to do then is actually put  this in to its own URL module inside of the app   that it's using, right to make that app reusable.  And also avoid situations that I just mentioned.   So to make these URLs, I can actually import  all of this if I wanted. Or I could just do a   quick import, just like this, right. So this is  a relative import of all the views that I have.   And it's important path and then we just declare  URL patterns. Back in our main configuration URLs,   I can go ahead and cut all of this out and paste  it into my URL patterns now. Okay, so these are   now those apps URL patterns. So back in my URLs, I  actually have a way to use those URLs. It's right   here. In the comments, it's already in there.  So all we have to do is import include, and then   bring in the example that it gives what is for a  blog app. In our case, we're using the products   app. And we just do it like that. And then put  a comma at the end. And now our URL patterns,   our main configuration, URL patterns are a lot  cleaner. And I can actually delete the imports   that are coming through there. So save this and  refresh in here, I'm getting a page not found.   What's going on here? Well, it's actually showing  me the stack level of my URL. So if I do products,   products, it works. But that's not what we want.  The only reason that that is the case is because   we haven't gotten rid of our original path that  was in there. So just getting rid of that will   solve that problem, there definitely is still  one more problem that we need to solve. So we   save this and refresh, I still have my products  rendering, as they were I click on this, it's   still bringing me to the wrong place. And this is  where name spacing comes in. So if we do app name,   inside of our apps URLs, to the name of our  app, so in my case products, right, you just   call it that. Now what I can do in my model is  just add that in here to products, colon. And   now my reverse is based off of the app itself,  or the namespace, and the URL name. So we save   that refresh. And now it's actually going to take  us where it should, this is a common problem. So   if you have to test this out and try it out on  your own, please go ahead and do that. And do   realize that having names on the URLs doesn't  mean that it's going to check to make sure that   those things are unique. So this is a way to  do that. I mean, you can change your products,   app name if you need to. And that would allow  your namespace to change and therefore, your   reverse method to change as well. As you can see,  this is why reverse is actually very important.   That's why this is the main reason is then when  I want to bring this app into a whole nother   project, my URLs, all I have to do is declare what  they are as the app name, I have to make sure my   users know or that third party package know, hey,  here we go, we've got our product URLs here. And   along with that namespace, I realized there's  a lot going on here. So you're definitely gonna   want to try this out multiple times, make  multiple apps, make multiple models, do the   views do all the things that we've done leading  up to this point multiple times on your own in   the next few videos are going to combine the  knowledge that we've gained over this series.   So what I want to make sure that you can do  is these steps here, one through eight. And   go ahead and do them now if you can. And I'm going  to use this model, but you can use any model you'd   like. But again, make sure you do these steps.  If you don't know how to do them. Just go back   to the beginning and start from there. So without  further ado, let's jump in to our views and make   the absolute simplest class based view. And that  is a list view. So the class article, List View,   and it's going to inherit from the list view. And  with the ListView, I have to provide something   called a query set. This is a requirement. So  article, but objects that all that's it, that's   my entire list view, notice I didn't have to call  a render, I didn't have to write a template name,   I didn't have to do any of those things. So with  this, I'm going to go into my URLs for this app,   I'm going to import it in here. And I'm  gonna bring it into my my default path   for it something that we've seen before, I'm  going to bring in that class name. And then   I'm just going to call as view. So it turns  it essentially into a function based view,   like we've seen in our product view page. Right?  These are all function based views. This is now   our class based view. And that's how you actually  run it as a class based view. So with this, now,   I'm going to go into my URLs and bring in my newly  created blog URLs. Okay, so I've got the URLs   module inside of that app. Let's go ahead and take  a look at all of my posts. I refresh in here. And   what do I see I see something that says template  does not exist. So by default, class based views,   look for a specific template. And the way it looks  for them is the app name, the model name, and then   the view name, or the generic view name. So in  my case, it is a list view. So it's going to look   for blog slash model name, underscore list dot  html. This is not a different going forward,   right. So let's let's actually Put this in  here as just sort of reference for us in the   future. So what we need to do is actually  create this, I actually already have these   items in here. So there's two ways on how I can  actually reference a different template. And we   can say template name equals to what template  we want. So articles slash article list, HTML,   that will allow me to use my very basic templates  for article list. Right, or I can go based off of   the generic one, I'm not going to go based off  the generic one, I just wanted to show you how   you can override those templates. So I refresh in  here. And now I've got that list coming through.   The next most simple class based view is, well,  it's our detail view, I'm actually going to copy   the article list view, and just change it with  detail view. And just like that, copy this,   bring it into my URLs come in here, I'm gonna  keep these things in order. This is just personal   preference. Okay, and then down in my URLs, I'm  going to replace the detail just like that. And   I'm going to change the keyword argument to pk.  I've got my template here already. It's very   simple. So I'm gonna go ahead and go into that  first article that I have there, it is not really   that hard to do, it's actually very easy to do.  So of course, if I didn't override the templates,   what would happen, I would get something like  this. And if I changed the keyword argument   to back to ID, what would happen, I would get  something like this. So you can absolutely have   your own lookup if you want. But by default,  it's looking for the keyword argument of PK,   or slug. So those correlate to different fields in  the model. So PK is also known as the ID field. So   Id actually equals to PK but it stands for primary  key for a little bit more advanced. But if we try   to look up by slug, let's just change the URL to  being slug the keyword argument URL to slug it   saying that it can't resolve this into our field.  Well, these are our only options, active Content   ID and title. So let's go ahead and go back to  ID and then override something in our view. This   is the def get object method. This is built in to  class based views, especially with detail views,   list views, it doesn't make sense, right? Because  a detail view wants one thing, or all this view   wants a list a query set. So let's go ahead and  get this by using a method we have seen before.   So get object or 404. So all we're going to do  here is return get object or 404, the actual   model name itself and then we want the ID. Well,  how do I actually get the ID from the URL? Like   how do I get this keyword argument from the URL,  it is quite a bit different than the view for it   right? The view for that detail view, it's passed  into that general function. But on our class based   views, it doesn't work that way. So instead, how  it works is we can use self dot keyword arcs dot   get ID. So this is the actual keyword arguments  that are being passed through that URL. You   can see what they are by printing them out. But  this is how we would actually override what that   keyword argument is to our URL. And then we can  look at our view. And what do you know, it comes   back, and it works just fine. So it's very similar  to what we've seen before, but it's just slightly   different. Now I understand that this probably  feels a little bit more confusing than this. The   main thing here to understand is class based views  inherit from a lot of different pieces. And to   override its primary function is just get object  detail view, the primary function of a detail   view is to render a template from a specific  object. Now, if I got rid of this query set here,   and refreshed, it would still work. I actually  don't need that query set. What the query set   does is it limits the choices available for that  detail view. In other words, let's take a look   at that. If I change this to being like, filter  ID is greater than one. Don't worry if you don't   understand what that is, but if the ID is greater  than one and I changed my URL back to that primary   key. Again, that's the default, we're overriding  that default Chrisette. Now, if I refresh in here,   it gives me a page not found. That's because  the default query object is not inside of this   query set, it does not exist in there. So that's  something that's really cool too, and probably   hopes that hopefully, this makes you want to  learn more about query sets. But either way,   I'm going to go ahead and leave that commented  out, leave that object in and leave the URL back   as an ID, because this is almost identical to  what we've already done with our other views.   To ever create or update view, we want to make  sure we have a model form. So this model form,   we're gonna go ahead and import into my views.  So from dot forms, import model form, and then   I'm going to go ahead and create my view. So I'm  actually going to Well, I mean, can I copy this?   Can it be the same? Well, it can be definitely  very similar. So we'll call it article create   view. And there we go. And I'm going to call this  create, right? So I need to make that template.   Article, create HTML. And much like product,  create a can just render out a form. Very simple.   So we got our view here. Let's go ahead and bring  this in to my URLs. And again, create as view,   open up that path. And let's go into blog create.  Okay, so we're missing something here. It's saying   using model for mixing without the fields  is prohibited? Well, if we look at our view,   we see that we actually didn't bring in our model  form. So what if I just did form class equals to   Article model form, save that refresh, there's  our form, if I ran through this, it would actually   save that data, it would work by default. And  it's going off of all of the validations, if any,   inside of my model form, again, those validations,  the ones that we did in product model form. So if   I wanted to validate the title, I would say clean  title, those sorts of validations. And also the   built in ones as well. So this view does that for  us. And so we still have that same query set. And   we also have a method called form valid, takes  in self and form. So what we would say here is,   this is actually the form valid data. So I can  actually do print, form cleaned data. And then   I'll just return super the superclass the built  in the default of form valid of that form. But   this will allow me to see what data is actually  coming through here. So if I refresh, new title,   this is my second post, I hit save, I do get this  error. This is critical, we will adjust this. But   if I look at my terminal, before that error, I can  scroll up and I see that clean data. Okay, so what   is this error, get absolute URL, that is a method  that should be done by default inside of your   model. So if we look back in our list, those items  are still there, like it actually did create that   item, except didn't go anywhere. So if we create  this get absolute URL method, get absolute URL.   And well, I want it to be based off of reverse,  like this one. So if I copied my other one, I   would just do something along these lines here. I  know I'm sure cutting things, but you should know   how to do this already. Okay, and then the app  name is articles for reverse. And it's going to be   article detail. Okay? So the reverse function is  to go to that detail view. So now let's go ahead   and create another post and say, new one, this is  a new post, we hit Save. Now it actually takes me   to that URL. So that is a critical method for the  get absolute URL method. And part of the creative   view. It's actually also part of the update view  as well. But the main thing here is I can also   change where I want that to go by just overriding  the success URL like this, or define get success   URL and you can return some path. That is another  way to override But but the default method works   really well for us, because chances are good after  you create an article, you're probably gonna want   to look at it. So the the actual next part of this  is pretty simple, we can copy this create method,   I'm going to put it underneath my detail view,  and change it to my update view. So article   update view. And much like our detail view, I'm  going to be updating a specific article. So I   can just use that get object method again. And  well pretty much get rid of everything else,   I don't actually have to change the template,  I can bring this now into my URLs and grab this   change like that. So if I wanted to go update it,  I would just type out update, whoops, not updated,   but update. And we might need to make sure  that we save everything. Okay, go to update,   and this is my third post, I had save, it brings  me back to that method. So the Create and update   are almost identical. The only difference is it  actually grabs an object or an instance of the   thing it's trying to change. Still using the same  form, still using the same query set. We want to   remove an object, we just use the Delete view. And  it's very similar to the detail view. So article,   delete, view, and delete view. And then  we're going to use a different template   called delete. And then again, we still want that  get object method here. And my actual delete form   is identical to the one that we created a product  with the exception that I called it product here   and post here. So we save that we save our views  here, do some imports. And bring in a view name as   view uncomment this out? Same stuff. So let's  go back into a post, let's say for instance,   post two and delete it. Do you want to delete  this? We say yes, again, we don't have the success   URL here. And in this case, it wouldn't use the  get absolute URL method. Because Well, the object   no longer exists. As soon as I say yes, it deletes  it from the database. So this is not even seen,   because that object is gone. So what we need to  do is set one and instead of setting the actual   string, so like success URL to something like  blog, what I'm going to do instead is I'm going   to bring in my reverse call. So from Django dot  URLs, import reverse. Actually, let's put that   right under here. And then I'll just go ahead and  say define get success URL takes itself. And it's   going to return reverse blog list view, or, you  know, whatever we have here, which is actually   article list. Good thing I looked. So change it  to Article list. And this is also articles. Okay.   Right there. Cool. So now this is our new delete  view. I can't leave that query set. But again,   it doesn't matter just like the detail view,  because of my get object call there. And I save   that, and now I go to delete. Do I want to delete  it? We say yes, it deletes it, it brings me back   to all of my posts. Very simple. And something to  note is that error, the Delete error. If I don't   have that get absolute URL method, or rather  get success URL method. And I try to delete   something and say, yes, that error actually  prevents that deletion, unlike the creation,   just something interesting to know. But that's  class based views. That's that's the gist of it.   Here is a fairly standard function based  view. And all it really does is render out   a template that we already have. In granted,  I made a new app for this, I made some URLs,   and I added it into my settings, as well as my  URLs. So make sure you know how to do that. But   I have this function based view. And if I look  at it, this is all it is. It just renders out   a template, not a huge thing going on here.  Now to convert this into a class base view,   we're going to inherit from a class called view.  So this is the base view class. So base view,   class equals to view and all I'm going to do is  say class, and whatever view I want to call this,   in this case, I'm gonna call it course view. And  again, we're going to pass in that view there.   So to have the exact same function work, I can  bring it right over So that function based view,   I'm now turning it over here. But if you remember,  our actual name for a function based views don't   really matter. But inside of a class based view,  they do matter. And they're correlated to the   HTTP method that it's trying to handle. In other  words, Git is the default, so Git will run here.   But like, if you were submitting a forum like  fo RM, you would often use the POST method. And   that's actually how you'd handle a form. We'll  get to that later. But for now, we've got our   course view, we'll import this into our URLs, we  will render that out, comment out our old one,   our function based view here, save that and  refresh in here. And we had a little issue,   we have to actually add in self here as well.  Because if you are familiar with Python, when   we say something like a new OBJ, or a new object  of a class, you often do something like that. And   that object is an instance of that class. So to  reference something like get, we have to actually   reference self inside of there. And with that, we  should solve that error. So if you see something   like this, that means you did that same error I  just did, which is rather important to see. And   now it's actually rendering out that template  just fine with that standard, get method. And   you can print out the various methods if you'd  like is request method. But notice that these   are identical with the exception of the fact that  this isn't a class. So one other benefit of doing   this is saying something like template name equals  to about HTML. And then we would just go ahead and   say, self dot template name. And that renders  out roughly the exact same thing. So this is   pretty cool. The other aspect of this is literally  coming in here and changing this template name, to   contact dot html, save that refresh in here, what  do you know, my template has actually changed. So   that's one of the huge advantages of using class  based views is how easy it is to change things.   So we now have this model in here, and I'm going  to bring it into my view to have this being a   detail view, how to actually handle that. Now,  to do it, we want to pass in a parameter from   our URL. So inside of your urls.pi, inside of the  app, we are just basing off of our products URLs,   not any different, they're nothing new. So I want  to actually make both of these templates be able   to work. So to do this, I'm going to pass in ID  equals to none, ID equals to none means that the   ID is no longer required. When you do it with just  ID, that means that argument is required. saying   that it's done means that we have a default  here, you could also set another default,   if you like. But basically that means that these  two template or these two class based views, will   actually render just fine. Now, let's actually  take a look at this. And what I'm going to do with   my standard template is I'm going to do courses  slash detail, or rather coarse detail to go along   with the detail view generic view. So I'm gonna  go ahead and make my folder for that templates,   new folder and their courses, new folder, or  a new file on there saying course, detail that   HTML. And I'm going to go ahead and just copy  and paste something I've already done before. And   just use the title because that's the only field I  actually have in my model. Okay, so I now have the   class based view running twice, but two different  template names. One is contact HTML. The other one   is well, going off of the default of what I set  right here. So let me go ahead and save that. And   let's go ahead and run it out. Instead of courses,  if I refresh in here, contact is still showing   up. If I go to one, or some sort of detail,  I have an empty template. Now why do I have   an empty template is because I haven't passed any  context into this template itself. So to pass that   context, and we'll just do from dot models, import  course. And we'll go ahead and do get the shortcut   get object, or 404. And I'll just say, object,  or rather OBJ get object or four, four course   ID equals to ID. Okay? And since I have a default  being none, I'll say if Id is not none. Meaning if   the past argument is not none, then I'll go ahead  and say this is what the OBJ is. And I'll also set   my context up here. So then I can just augmented  here with object equaling to OBJ. And then real.   Or rather, we want to pass context here. So we  save that refresh. And there says hello world,   that is the name of my first object, which I could  also add in just the ID to just double check that   I'm doing everything correctly. Save that. And  there we go. We've got our ID, and hello world.   Let's go ahead and create the raw ListView. Very  simple Course List View and inherits from view,   we can add in a template name here, much like  we've done before. And I'll just call this course   list. And then I'm going to do something new. And  that is setting a query set here, so coursed on   objects that all and then I'll just go ahead and  do find get self request arcs and keyword arcs.   And then we're just going to go ahead and return  Well, the render of the request, the self dot   template name, and then my context, I'll just put  in a dictionary here and say, object list equals   to self dot crueset. For better illustration  purposes, I'll just leave it in as that context,   just like that. Okay, pretty cool. So I bring this  into my URLs. And now I'm going to go ahead and   you know, get rid of this other one, and leave  that in as view here. And then in my templates,   I'll go ahead and say Course List dot html. And  for my product list, I'll just copy that one   there. And I'll not worry about a link. For now  I'll just show the actual title, save it. Okay,   and go back into our courses, just that one list.  And we see that I got two in there. Very simple,   very easy. But I want to go one step further to  get it closer to how the generic view works. And   that is defining the get query set method  here. And what it's going to do is, well,   it's going to return self dot query set. And  then, in my context, instead of query set itself,   it will just will call self dot get  query set, or this instance method here,   instead. So if I save that refresh in here, it's  the exact same. However, if I actually inherited   from this and said class, my list view from that  course list, so let's just put it right underneath   here. And I said query set, and I put it equal to  course dot objects, dot filter, ID equals to one,   this will actually give me a list of items, even  though it will only give me one, and I brought,   bring this into my URLs, and use that one  instead, save that refresh in here. Sure,   make sure I've saved everything. Okay, I refresh  in here, what do you know, there is the biggest   benefit of using class based views is this  inheritance property. Of course, I'm not actually   going to end up doing that. But I wanted to  show you for illustrative illustration purposes.   When you create something, you want to accept  two methods, that's the get method and the POST   method. So I'm going to go ahead and grab the  course view here, paste it over and call it   course, create view. And we have our get method in  here, I'm gonna leave it in as empty context. And   then we want to have our POST method, because when  you actually create something, you post it to the   back end. So we want to make sure that we have  post, really simple, I don't actually need the   ID argument passed through here. We're not using  that. And then of course, the template itself is   going to be course, create, now want to bring in  my form, which is from forms import, and the name   of it is course model form. And I want to actually  initialize this in two places, right? One is the   get method. We'll say form equals to the course  model form, make sure that it's empty, just like   that. And then inside of my context, I'll have the  form of being passed, because my create template   has that need. Okay, so we save this, let's bring  it into our URLs and add it in as a path. Okay,   really simple stuff so far. Let's go ahead and  go To that, end, we see a title here. Okay, so   if I type some stuff out and hit save, it doesn't  seem like anything happens, well, nothing actually   does happen, because our view actually accepts  post data, but it doesn't do anything with it.   So what we have to do is come in here and grab the  request dot post, whatever that data is. So again,   same context, we bring it in here, just like that.  Okay, so this will allow me to actually have the   form data coming through with whatever the context  is. So let's go ahead and create something. And   hit save, seems like things have happened,  let's go back into my courses, I still don't   have anything in there. Because of course, I still  need to come in here and say, if form is valid,   then I would just do form dot save. And that would  give me the actual method to save a model form.   Now, I want to test this method to make sure that  something like this actually renders out. And to   do that, I use something called field validation.  So in a form, we can actually have validation with   clean, underscore, whatever the field name is. So  the field name, I'm validating is title. But it   could be any of the model fields or any other form  field that you might use. In case you forgot about   that. So we're going to go ahead and come in here  and actually do it. So title is equal to self dot   cleaned data, dot get, and then the field name, of  course, and we'll say if title dot lower is equal   to something like ABC, then we'll just should  go ahead and raise forms dot validation error.   And this is not a valid title. Okay, so this is  only on the form level, right? It doesn't do it   on the model, it only does it on the form. That's  a key distinction here that you should remember,   obviously, we're not going to touch it just yet.  But that's key distinction. So now that we've got   that I didn't change anything in my view, let's  go ahead and try it out. Coming back in here,   I just type out ABC, hit save, I see that it says  this is not a valid title. So in other words,   what our POST method is doing is it's actually  coming through and initializing what needs to   happen. Now there is one other thing that  you might consider doing. And that is,   once it's valid, you might actually want to  rerender the form. So let's say another title,   I hit save, it stays in there, although I might  want to create another form or another course   or whatever it is that I'm building, right.  So I want it to be empty, I want it to be in   its original state. So to do that, all I need  to do is reinitialize, the actual form itself.   or update view combines the things that we just  did create and also detail. So we've got this   update view here. And we have two methods that are  going to be there for sure. And they're the same,   basically all they're doing right now is  rendering out the form. So it's really not   a whole lot different than the Create view as  it currently stands. But the thing that I want   to actually adjust is this get object method.  So this method itself is going to override what   you would typically do for your detail view, you  would have a method in there called get objects,   so then you can use it in your various methods.  Otherwise, right, so like, as we've done here,   that is actually how we're going to call  that object. So what I want to do, then is   just pretty much grab the same data that I've done  before, which is this right here, this get object   or four or four related stuff, right here, right,  so this is going to grab that detail. And to grab   the ID, we just do self keyword arcs dot get ID,  those are obviously the keyword arguments that are   coming through on our URL, like we see here, and  ours right now is an integer with the name of ID,   and this will actually grabbed that object for us.  So I'm just gonna go ahead and say OBJ equals to   none, and this will grab that object. So now we  have some object inside of our context. So this   will work on both our get method as well as our  POST method, it will have that object in there.   And if we look at our template, it's a combination  of that detail view and that crave view form. And   now, what we'll do then is actually update this  item. So we have this item here. All I need to do   is pass it in to my form as instance. So instance  being OBJ. And I want to have that also down here   in addition to the request dot post. So this is  grabbing that post data along with that instance,   this is initializing that looking to see if  it's valid. And if it is, then it will save   everything for me. And then finally, my template  has the method of post. And the form really hasn't   changed. So let's go back in here. And let's take  a look, I've got my update view here. Now we got   a context error. So we want to make sure that we  have context defined. And that's this right here.   That should actually not be their little mistake.  Sorry about that. Okay, so we come back in here,   a Hello World, I'll just change it to being Hello,  I'll hit save, it changes it to Hello, I go back   to the detail view, it's still Hello. If I go  back to the update view, and change it to ABC,   and hit save, it does validation again. Now, you  can probably see that this is redundant code. And   it is and that's because of how we had to do it  by raw detail, we started doing stuff that's not   redundant code. But really, at this point, it's  like you might as well use that generic class   based view, the built in classes views that we've  already gone over, right. So I mean, this is just   so much cleaner and simple. But the idea here is  really understood, this is the raw version of it.   Continuing off of the idea of the update view, we  have this delete view, it's pretty much identical,   except we don't need to bring in the  form. And then the final thing that   we would do is actually have a redirect.  So we actually delete the objects on that   POST method and then redirect it somewhere  after importing the redirect. And of course,   my URLs, I update that. And then in sight of my  templates themselves, the form that's in there,   I just rendered out this raw form, as we've seen,  so we want to do delete the course instead. And   the idea here is that we render out this sort  of confirm message, and then post that message   saying, Yeah, we confirm, once you do that  post message, then you actually delete that   item. So let's go back in and take a look  at our courses. I'm gonna go into course,   three, delete, and there we go. So we do want  to delete the course another title, we say,   yes, it deletes it redirects. Really, really  simple. But this is the wrong way to do it. Makes   sense, or part of the reason that classic views  are so good. What it makes it does is it allows us   to extend a class based view with some new code.  Let's take a look. So what I'm gonna say is class,   and we'll call this course object mixin. And  it takes in just object as its default object   is just a Python object. And then we're going to  go ahead and say that we'll give it model name,   or model class or just simply model. And we'll  give it to be none. And then we'll do a method   called get object. And then we'll return something  related to what we've seen before. And in fact,   we will return this right here. So we've  got our object here. And instead, of course,   we'll just do self dot model. And of course, the  default itself is going to be core. So we'll just   leave in that, that default. So this is now going  off of this, right. The next thing is let's go   ahead and just say URL lookup, or, you know,  lookup, simply, and this is going to be equal   to ID. So now down here, I can just change this to  being self dot lookup. Okay, so that's pretty much   it. This will help me reduce redundancy inside  of my code. So I can grab this object mixin,   and just bring it into my delete. And quite  literally get rid of that get object method now,   because it actually works in here, it's this right  here is going to call the mix ins version. And you   want to make sure that you put the MCs in first,  and then the class based view or the final class   last. And then we can do the same thing for  update. We can do the same thing for create,   or Well actually, we don't need it and create but  we also don't need it enlist. And then finally   detail. Right, so the object down here, instead  of being all of this, we would just do context   object equals to self dot get object. Because  the rest of it is going to handle as we expect,   right? So it's going to raise that error, if it's  not there, just like that. And it's going to look   up by that field. Unfortunately, the lookup is  going to have to be identical to what we've got   here. Right. So this this makes things a little  bit more challenging doing the look of like that.   So I'm gonna leave it back in as ID. But the  general idea here is that we would, in theory,   be able to change what the lookup would be. But  in my case, I'm just gonna leave it in again as Id   but that's how this actually works. makes sense to  actually work just like this. So now that I've got   all that, let's go ahead and take a look inside of  courses. Let's go to the first one. Still working,   update, still working, delete, still working.  So we've now reduced the amount of code that   we have by creating our own mixin. And of course,  as you see, we can make it more complex and once   you make it more complex, then our class  views are even that much more superpower.
Info
Channel: freeCodeCamp.org
Views: 3,040,403
Rating: undefined out of 5
Keywords: django, python django, django tutorial, django course, python django course for beginners, django 2.0 tutorial, django docs, python django tutorial, django framework, python django course, python django framework
Id: F5mRW0jo-U4
Channel Id: undefined
Length: 225min 41sec (13541 seconds)
Published: Wed Jan 02 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.