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.