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.