What is up, how's it going? This is kazi from
clever programmer calm. What I wanted to cover in this series is Django. And what I wanted to
cover was like the most commonly referenced Django documentation, I personally couldn't really find
any videos of people like covering it. So I just wanted to do that. Because, you know, I see, like
everybody who starts learning Django, this is the first place you're gonna go to like the docs,
the Django official documentation that shows you how to, you know, do their getting started guide.
And so I just want to kind of cover that in this series. And just right now, I just want to kind of
cover the overview, and then we're gonna jump into actually, the parts of the tutorial, okay, and
you're just gonna follow me along. Alright, so I'm going to cover this kind of touch on this. So
if you have some experience with it, it will make a little bit of sense. So designing your models.
So in Django, you can kind of design your database and models like this, you don't need to type in
raw SQL queries or mess with too many ora, or MS is just simply classes. So it's literally
like Python and object oriented programming, and boom, you have stuff populating your database,
which is pretty cool. It also has a built in kind of API. So it says, you know, as soon as your
models are done, the API is created on the fly, no code generation necessary. Okay. So here, you
can see that if you create a model, like let's say that you're creating an app, right, it has
reporters, and your app has articles, you know, well, what you can just do is just be like, hey,
reported, I'd objects dot all. And they'll tell you how many reporters are there. For example, if
you made a game app for like, let's say, a street fighter, and you did fighter dot objects at all,
it might say empty set, which means you didn't put in any fighters yet, right. But then let's say
you create a fighter or a reporter with the name john smith, and you save it. Then when you check
objects at all, all of a sudden, you'll say, hey, reporter john smith actually does exist. So that's
pretty cool. And a really nice way to interface with it. And then also, you can search for things
in a really easy way to so you can search in your database with an ID. But you know, a lot of the
times what a more human way to search instead of an ID is like searching with, what does the name
start with or if the name contains the word myth, which Smith actually contains, and l match it.
So then what you can do on your front end later is right now like you're not going to have your
client interface with draft from the code command line, right? What you can do later is then give
them a front end and interface so then they can actually type it in the search bar and look up
john smith or typing myth. And they'll still find john smith. Kind of like when you guys go to like
Shopify stores, or, you know, YouTube and type in a videos name. And even if you're off, you'll
still find it, it's using this contained search mechanism, which Django comes built in with.
Another thing I want to touch on is, yeah, so if you have your model, you can register them in
the admin interface with just a simple line that says admin dot site dot register. And then that
model votes lets you create the article model, you can now register it in the admin interface.
So then you can go and point and click an admin interface, and then delete, or create new articles
or whatnot, right? For example, when you have a WordPress blog, you know how you have an admin
interface there. And you can create a new blog post or delete a post or edit, you have full crud
functionality? Well, that's what it mimics by you just doing this, right. And that's you creating
code from scratch. That's kind of powerful. And then, obviously, lets you design your URLs,
right, so how do you want your URLs to be, so for example, you can have it like, you know,
my ab.com slash articles slash the year, followed by whatever, right, so you can create your own
URL, parameters, and whatever. So this is pretty standard. But it looks Django lets you do it in
a really clean way, especially with Django 2.0, their new latest release. Alright, so writing
your views is also pretty easy. You can have a just like return HTTP response or HTML file you
made. So for example, here you can see, we render and return like this archive dot html file. So
if you create a HTML file in your templates, then it's going to be there. Again, if you're
watching this and you're like, I'm a complete beginner and I have no idea what the heck you're
talking about. Don't worry. If this part is just not making any sense, skip a little bit ahead to
the part where we jump into the tutorial. This is just for People who are maybe coming from other
frameworks, and they want to grasp how Python and Django is working, okay, so you do need some
experience to understand what I'm talking about here. And then yeah, templates are using, it's,
it's using Django templates, which is kind of like Jinja. I'll go into this later. So at this point,
like, let's just get started. Alright, so for your installation, all you really need to do is make
sure you have Python installed. So for myself, I got Anaconda installed, which is, which is what
I would recommend for you. So if you do Anaconda, download online, kind of install that. And that's
pretty much all you need to go on. And then obviously, install Django as well, which I'll show
you in one second, okay. All right, and then you can go ahead and create a project. So we're going
to just get started from scratch and follow along with this tutorial. So let's, let's get started.
Okay, so I'm gonna open up my command line here. So I'm just gonna open up my terminal. If you're
watching this, you can open up your, you know, CMD on Windows, or, what I recommend installing
is cmd. Er, on your Windows. And, yeah, basically just see if you have Anaconda installed. And if
you do, and if you type in conda, this distinction come up, okay. If you don't have Anaconda
installed, that's okay, you can still follow me along. But what I'm doing here is kind of like
for best practice. So if you want to do it, like the best practice way, then I recommend that you
get conda installed here, let me just make this a little bit smaller. Alright, so basically, what I
want to do here is first, check my J. So what I'm going to do is install my environment with conda.
Okay, so I'm going to do and, again, installing Anaconda. And like making you understand
everything about virtual environments is outside the scope of this specific tutorial. So you can
look up stuff, like how to install Anaconda on Windows, or how to install Anaconda on a Mac.
But I'm just going to go ahead and do conda. Or, first I'm going to create this project. So let's
see, I'm going to go to my GitHub. Alright, what I've also done is I have gone into preferences
in my atom. And I have went in under install, and I've installed terminal, platform meal ID
terminal, and I've installed it. So then the beauty of that is that when I'm coding, right,
if I'm coding, I can just pop open my terminal, right in here, and I don't have to leave my adult.
So I will do Django admin, start project my site, like that, and then go into my site. Okay, and
then I will come over here, and I will open, I'll go to GitHub, and then I'll go my site, and
then just click that. Okay, that's about it. This is just so if you guys are following along,
like I don't want you to get confused. Okay, I'm gonna open up my Chrome. So they're saying
that this is pretty much what it should look like. And for us, it does look like that, right? We have
my site, and it has all these files inside of it, and you can see my site, and it has all these
files inside of that. Okay. Um, and then they say, hey, just go ahead and run Python manage that
py run server. So let's go ahead and give that a try. So I'm gonna open up my terminal and how I do
that how I open up the little prompt is by doing Command Shift P. for you on Windows, that might
be a different command, like maybe Ctrl Shift P. But yeah, for me, that opens it up and then I
just click terminal pops open my terminal. I'm going to do conda create dash dash name. My site's
Python is equal to 3.6. And I will activate this environment. Okay, and now I will install Django.
Okay, so if I do PIP freeze, it should show me that Django and much other stuff is installed
Jango right here, so we're good. Alright, I'm just gonna make the font bigger so you guys can see it
a lot easier. Okay, so now, we're going to try to run this Python managed up py run server. And
we will go to this URL on our chrome and see if it shows us something. Okay, cool. So it says
install works successfully congratulations. And, believe it or not, this is actually pretty
exciting, because this is the first hint that your app is actually running. Okay. Now to
this, we're going to add a lot more features to it and make it really awesome. But right now,
it's being actually served over your localhost, and it's running, okay. And once we get it to a
point where it's doing a lot of cool stuff, we'll develop it locally, and then later on, or you can
even do is and put it online, so then anybody in the world can use your Django app. Let's go back.
And let's take a look at what the tutorial is telling us to do at this point. So it says that
you should see this stuff, and we do. And then it says, ignore the warning about unapplied database
migrations for now. We'll deal with the database shortly. Cool. And it says we have started Django
development server, which is a lightweight web server written purely in Python. We've included
this with Django, so you can develop things rapidly without having to deal with configuring
a production server such as paci until you're ready for production. Cool. All right. And they
say don't use the server in anything resembling a production environments tended for developing
cool, no problem. All right. And now they want us to get started on creating the polls, polls app.
Now that your environment a project is set up, you're set to start doing work. Each application
you write in Django consists of a pure hour of a Python package that follows a certain convention.
Django comes with a utility that automatically generates a basic directory structure of
an app, so you can focus on writing code rather than creating directories. Cool. All right,
projects vs. app. So what's the difference between a project and an app? Now, the cool thing with
Django is that everything is considered an app. Okay, so let's say that you create a website that
has a blog that has an e commerce capability. Now, the blog is considered a so let's say you created
this website with Django, right, the blog would be considered a Django app, and your ecommerce store
would actually be considered a different Django app. Okay. So there'll be two different apps that
your web application is comprised of. That's how Jango handles the logic. So basically, it's one
project that has multiple apps inside of it. Okay, that's pretty much what they're saying here.
Okay, so an app is a web application that does something. Okay. So a web blog system, a database
of public records are simple pull up a project is a collection of configuration apps for a
particular website. A project can contain multiple apps, an app can be in multiple projects. So you
can have one app that you build for one project, and you can actually have it in different projects
that you're doing, which is really cool. It's like plug and chug. Your apps can live anywhere on your
Python path. In this tutorial, we will create our poll app right next year, manage that py file,
so that it can be imported as its own top level module rather than a sub module of my site. Okay.
To create your app, make sure you're in the same directory as manage.py and type this command.
Okay, so now this command Python manage that py startup polls, we're going to do that, okay.
So, we're going to break our server with Ctrl C. case I did that I'm going to hit LS, and it looks
like I'm at the same level as my manage.py file, and if I had pwd, pwd will show me where I'm at.
And now, I'm going to do Python managed.py start app. And the app is called polls, I believe
just let's just double check. Okay, so now our polls app is created. And let's just take a look
inside of polls. Polls. Okay. So inside of polls, you can see that we have a bunch of Oh, actually,
let's look right over here. It's easier that way. So Paul's comes with migrations in net dot p y,
admin apps, models, tests, views. There's a lot of things That polls comes up with automatically,
which is really nice. But a lot of this stuff is, you know, just kind of empty. The main things
that you're going to be working with is models and views, okay, that's, that's the thing you're
going to be working with like all the time, when you're developing apps for yourself later,
you're also going to be playing around quite, you're going to be doing adding stuff to test
to make sure you can test your app as you're building it. And then migrations is going to
be important, because it's going to kind of let you time travel in your database. So when we keep
making changes to your database, with migrations, you can like roll forward to a certain time.
But let's say like things get really messed up, you can roll back to a previous point in time. All
right. So the disk directory structure will how's the poll application. So this is the directory
structure that we actually saw, okay. And now they want us to write our first view of view is what
lets you go to a specific URL, and then it returns some kind of response. Okay. So for example,
so Django works off of something called MVT, which is called Model View templates, your
normal apps, you know, node.js, or whatever those frameworks work off of MVC model view controller.
So to give you an example of this in real life, is when you go to google.com, slash, you know, when
you go to google.com, and you type in like cats, right? Or let's say you go to google.com. And you
type in whatever the response that comes to you, right, that maps to the current URL you're at. So
how does Google know to show you the Google logo and the Google homepage when you go to google.com?
Right. So google.com, when you type it in, it sees what your current URL path is, then it
goes into the Google code base. And then it finds this HTML file that says, if somebody goes to this
path that says google.com, then show them this HTML page that has Google's image on it, followed
by a search bar, and then shows you that, okay, so it returns a response, you request something
and it returns a response. If you go to apple.com, slash, watches, or watch, I don't know if that's
actually a real Apple URL, but like, let's just say you're trying to get an Apple Watch. Okay? So
if you go to apple.com, slash watch, how would it return to you all of their watches, right? So
what actually happens is apple.com slash watch will match that path in their code base. And then
it'll see if there is a HTML file that corresponds to it. And it'll show you that HTML file, okay,
as a response. And that's essentially what we're going to do. Well, we're going to have a very
basic version of it. So we're going to go in our poll slash views that py. So I'm in my polls, and
I'm going to go in my views that py. So when they say it, like this poll slash views that py, that's
what they mean. And in here, I'm going to say from Django dot HTTP import HTTP response. Right. And
then I'm going to go here, I'll say define index requests, take in a request, and then return
an HTTP response. And I will say, Hello, world, your ad. Let's do it with double quotes, because,
hello, world, you're at the polls index, right. And then they have a little comma here, this
doesn't matter so much, there's just a string. So it doesn't matter what you do. Make sure you
always save what you're doing, because otherwise it won't take any effect. So make sure you do
Ctrl S or Command S the whole time. So I just created this, but the thing is that it's not going
to show up. So now what I need to do is like, tell my app that when somebody goes to the home page,
yo, you got to show this exact this thing right here. Okay. This is the simplest view possible
in Django to call the view, we need to map it to a URL and for this, we need a URL con for a URL
configuration. To create a URL confit in the polls directory, create a file called URLs dot p y. Your
app directory should now look like this. So now notice there's a URLs dot p y here, which was not
there before. Okay, so we're going to go in our polls, right click here and create a new file and
call it urls.pi. Okay, And now in our URLs, r p y, we got to add from Django dot URLs, import path
from Django dot URLs, import path. And then we're going to do from import views. And then we're
going to do URL patterns. So what you want to do is try not to indent, but use four spaces instead.
Okay? 1234 if it doesn't automatically bring you to the right place. All right. And I want to
do pass. So if somebody goes to the empty path, then I want you to go into our views file and use
the index function. And we're going to call give it a name index. Okay? So what does this mean?
If somebody goes to, let's say, your website is called john, calm, right? somebody goes to john
calm, followed by nothing else. So not like john calm slash article slash blog, none of that is
just john calm your homepage. What happens? Well, then we say, going to the views file and
run the index function. So in under views, this is index function, I'll run that. We're
naming it index. So then later, if we want to, from our templates, or HTML, if you want to refer
to this specific URL path, we can just call it by index, no, reference it. Okay, the next step is
to point the route URL configuration at the polls, that URLs module. Okay, so you're all content, and
we got to point it to this. So Alright, in my site slash urls.pi, add an import for Django dot URLs
include and insert include in the URL patterns list. So you have this. So we're going to go in
our my site slash URLs right here. And in here, we're going to add this line, okay? Because we're
saying if somebody goes to the path polls, then run the polls, URLs. Okay. So from Django contrib,
import admin from Django, import from Django dot URLs, import include, comma path, okay. And that's
because we're gonna do the include thing right now, just like that. Okay, and then hit save.
So if somebody types in john comm slash polls, now we'll say, hey, try to match this pattern by
going to the polls, our URLs file. Well, where's that that's in the polls app. And it's this file
right here. So then it'll go to this file, and then it'll match this first guy, and they'll say,
Okay, I'm going to run the home function, okay. So anytime somebody goes, anything, polls will refer
to that file, that URLs file. Alright, the, this is what they're basically saying here. The include
function allows referencing other URL cons, whenever genuine counters include, it chops off
whatever part of the URL match up to that point, and sends the remaining string to the included
URL con for further processing. The idea behind include is to make it easy to plug and play URLs.
Since poles are in their own URL client, they can be placed under or any path and that will still
work. Okay, you have now wired. So now it says, You should always include, you should always use
include when you include other URL patterns. Okay. And now it says you have now wired an index view
into the urine. Let's verify it's working. Run the following command. Okay, so now we're going to run
this thing. And we'll go to our localhost or this HTTP is port over here. And hit run. And now we
are getting an error. Oh, yes. Basically, you have to do slash polls, okay, of course. Because it's
not a home page thing that we've added to because I just saw this and I was like, oh, homepage, but
it's because we got to go to the polls path. Okay. So everything after so it's like, when you put
this online, when you put this app online, right, it will essentially be like, your app comm slash
polls, is where you'll have to go to and then I'll know what to do. Okay, so let's say you're at the
polls index. And that's exactly what we see. Now. Cool. Go to this in your browser, you should
see the text which you define in the index. The path function is Pat is passed four arguments to
require In view and to optional, at this point, it's worth reviewing what these arguments are
for. Alright, so we're not going to go into too much detail is going to be like still casual,
and we're gonna keep moving forward. We're gonna do part two of the official Django tutorial, we
have already done quite a bit of stuff, right, we've gotten our local servers started. But what
we want to do now is in this video, we're gonna actually cover our admin interface, and we're
gonna actually start playing around with it. So it's gonna be pretty exciting. I hope you're
willing and excited to see how that works. Okay, and we're going to go through this one a little
bit faster. So Okay, so first thing we want to do is like, look at the database setup, which you
can, frankly ignore if you're new. But later on, like, this is something that you should read.
But for now, we're only going to focus on this command that says Python managed up, py migrate.
Okay, so this is a complete continuation from the last video, okay, so make sure you're caught
up on everything from part one, I'm gonna open up Adam. And I'm going to break out of this by
doing Ctrl. C, and I will do Python managed up, py migrate, and it should give you a bunch of
okays. And what that did is created these tables that weren't created before, okay. So they're all
created, like stuff with usernames and emails, and permissions and all the stuff that it has to do
on the back end. Okay. All right. And from here, we're going to go on, and we're going to try to
now create models. Alright, so we'll define your models, essentially, your database layout with
some additional metadata. How Django models work is their philosophy follows the DRI principle,
which stands for do not repeat yourself, which is a really common, commonly used acronym
in the programming world. And it emphasizes using logic that helps you never really repeat yourself,
right. So for example, just to give you a simple example, imagine if you had to print out a letter
or print out the word Boom, 100 times, you could keep writing print, boom, print, boom, print,
boom. Or you could do it in the dry way, which is write a for loop that prints it out 100 times,
okay? So that way, it allows you to stop yourself from repeating, and just helps you do it at once.
Now, when you start abstracting it and taking it to a higher level, that might mean taking your
code from basic, basic code, and modularizing it into a function or into a class or into a package,
things of that nature, okay. And that's the same philosophy Jango goes off on so instead of like,
repeating yourself over and over again, it lets you create a class, which then creates models out
of and handles a lot of that stuff for you. Okay, so we're going to create this these models, okay,
and basically what we're going to be working on in our simple poll app, we're going to create two
models question and a choice. A question as a question and a publication dates, almost imagine
like a spreadsheet. Let's say you create a new sheet in the spreadsheet and you call the sheet
question. You have column one that says question tax, column two that has a publication date. So
question tax on your first row might be, what the hell is going on? And the publication date may be
like, February, whatever. And your next question might be like, when is causing you going to make
the next piece of content, stop making all these crazy videos where he's outside talking to the
camera, and then your publication date next to it, right? So that's how I want you to picture when
we create these models. Alright, with that said, let's move on. Our choice is going to be its own
spreadsheet or its own sheet. Okay. And basically, what it does is a choice has two fields, the text
of the choice and a vote Tally. Okay. So the chat text and the vote Tally. And then the question
that you get to choose is actually referenced from the question model. Okay, so let's actually
now write this code out. So let's go to our polls. And I'm just going to copy paste it, I recommend
that you actually write it out because it's really helpful exercise for you. But just for a time, I'm
going to go through it faster, we're going to put it I'm going to paste it right here. Okay,
I'm going to save it. Alright. Now we have to activate our models. Okay, so I'm going to go into
my settings, my site slash settings. And inside of here, I want to tell Django that we actually have
this app installed. Okay. So what I want to do is polls dot apps dot, I think it's polls config like
that, okay, and make sure to put a comma after it because after all it is a list with 1234567
elements. Okay, so now Django knows to include the polls app, let's run another command. So up
until now Django had no idea what this thing that you created this polls app. But now that you went
in my site and added this under settings and added to your installed apps, now it knows that it's
actually there. Okay. It's the equivalent of kind of like, let's say you downloaded an app on your
Mac or your windows, but you never installed it, right, like downloaded a game, but you never
installed it's kind of like that. So we just installed it by doing this. Okay, and now what we
want to do is let's run another command, Python, manage that py make migrations polls, okay? So I'm
going to come in to my command line. And again, to activate your virtual environment, you'll
do source activate, followed by the name of your virtual environment. And to deactivate your
virtual environment, you will do source deactivate if you're on a Mac, if you're on Windows, and all
you need to do is activate, followed by the name of your virtual environment. So in this case,
it will be my site. Okay, so since I'm already activated on my virtual environment, I'm just
going to do Python manage that py make migrations, poles. And now you see that it says Create model
choice, create model question, add field question to choice, okay. All right. By running make
migrations, you're telling Django that you've made some changes to your models, in this case, you've
made new ones, and that you'd like to change this to be stored as a migration. Cool. And this is
effectively what the sequel will look like for this. So this is not something you have to worry
about. If you're a beginner, and you don't even know what SQL is totally fine. But if you have
a little bit of experience, check it out. What's really cool is like a bunch of this code that you
would normally add, like generally anything to do with databases requires you to know SQL or write
SQL, okay, SQL. And for you to write raw SQL, it looks pretty complicated, right? Like, for
example, if you go here, there's a lot going on. If you write SQL every day may not be that big of
a deal, but it's a lot going on. Whereas Django, it's automatically generating all this code for
you. And you don't actually even have to worry about it, I just showed it to you. So you can see
what it actually looks like, on the back end. So that's what they're showing here. And we're not
just gonna, we're not going to worry about that. And since we made the migrations, we're going
to commit those migrations to our database by doing Python managed.pi and typing in migrate.
Okay, so now it says applying polls initial, and it says, Okay, if I go to my migrations, I
can also see this specific migration that I made, okay, and I can read this migration whenever I
want. Do not mess around with this file too much unless you know exactly what you're doing. Okay,
cool. And now we're going to play with the API. Another thing about migrations, when you get
a little bit more advanced, it allows you to update your database without ever losing track
of it. So flask has kind of a weird migration thing going on, whereas Django kind of comes with
it. And so it's databases a lot easier to play around with. Like it says, migrations are very
powerful that you choose your models over time, as you develop your project without the need
to delete your database or tables and make new ones. That's generally what you have to do. If
you're working with, you know, like just kind of working from scratch. It specializes in upgrading
your database live without losing data. So again, this is going to be really powerful and helpful as
you get more advanced. And as you do more things with models. So now let's play around with the
API that actually Django gives to us for free. Alright, so we don't actually have to write it, it
just kind of comes with it. So I'm going to go and instead of just typing in Python, I'm going to do
Python manage.py shell, okay. And here, I will do from polls on models, import question, comma,
choice. And then now we can play around with it. So since we don't have any questions in our
system yet, when we actually look up questions, and the objects for it, it should show us
empty, right, because we didn't create any thing from in the question model. Guess if I do
this at all. It should show us none. And that's exactly what is showing us like, hey, the query
set is actually empty. Now what we want to do is create a new question. All right. Django expects
a time date use time. So now instead of this and it will do the right thing. Okay, so we're gonna
go from Django dot utils import timezone. Okay. And what does our question take? Remember, if we
look in our questions model, it takes two things. It takes a question tax and a publication date.
And that's what we want to give it to create a new question object, okay. So pretty much typed
that in what is it saying? It's saying, Hey, I'm creating a question object. This question.
Class essentially takes in a few things, question tax and publication date, and I'm using keyword
arguments. So I'm putting question underscore text equals. So for the question text, it takes in
a car field. So let's go actually here in models, and you can see that it takes in a character field
right here. And that's why I'm actually passing it in as a string. And then publication date takes
in date time field, and that's why I'm passing in the timezone dot now, object, okay. And just
gonna hit enter here, and now, Q is created. So I should be able to do something like, well, let's
follow along with their documentation is saying, but if we actually do this now, right question
that objects dot all let's see if it shows us. So that's because we haven't saved this yet. So once
we save it, it's going to show up in our as one of our created objects for a question. So let's
follow along. So now it says, save the object into the database, you have to call save explicitly.
So we're going to do that I'm going to say q dot save. And let's try it again. And now look, it
shows us that there is indeed one question and that even has a number an extra one. Okay, but
it's not very helpful, because it's not showing us what that question is. Or it's not giving us
a very easily readable name when we actually use this API. So I'll show you guys how to overcome
that, too. Alright, so now it has an ID if you do q.id, it'll show you its ID. It says access model
field values via Python attributes. So I could do q question, tax. So that question text right
there. And they'll show us like, what's new, and I can do q dot pub location, date. And they'll show
me the date as a date time object 2018 two, which is February 19. And let's go down here. And we can
even change the values by changing the attributes and then calling save on it. Okay. So for example,
before we had the question, that's what's new, we can now save that question as What's up, okay.
So for example, I can do cute question, underscore text is equal to what's up kids at home. And I can
do q dot save. And now if I do Q, question, text, you'll see that it actually says what's up, right?
displays all the questions in the database. So now if I again, do this, which you've seen, it'll
show me all of the questions right. Now we only have one question. Okay. So if I wanted to add
multiple questions, I could do that. You know, let's say that we add q2. And then I do q three,
and then I go right over here. Instead of saying what's new, say what's poppin that, hit Enter. And
now if I do question dot objects, dot all you can see that it shows me Oh, sorry, I have to save q2
dot save q three dot save. And now if I do this, you'll see that it shows me I've one question
two questions, three questions. And I can even say for a question and question dot objects
dot all I can loop through it, print question, dot question underscore text like that. And if I
run that, it'll loop through all of these and then they'll print out the question text, okay, so you
can do it. This is just like playing around with xAPI and kind of getting comfortable with it.
Okay, and it's close. Wait a minute. Question isn't a helpful representation. You know this
object? So let's fix that by editing the question model in the thing. So that's what I was talking
about, right? Like, they're saying it in their technical terms. Basically what they're saying
is like, hey, look, this looks ugly as hell, and doesn't give us any information like what
this is about. So let's make it into something that a human can read and be like, Okay, I
get what this question is, and it's readable, right? So that's what we want to do. All
we need to do is add a string method. Okay, so we're going to add string representation to
it, you'll see what I mean, in just a second. So right now just shows us like, blob like whatever,
right? Well, we're going to do is under the class question, we're going to add string method like
that. Okay. And it's going to take in self, and then we're going to say return self dot question
underscore text, like that. Okay. So instead of showing us this, wouldn't it be nicer if it showed
us that question? Because that's a much easier way of identifying what that question is, when you're
just looking at the list. It's just more readable that way, okay. And we're going to do the same
thing with choice, we're just going to go here, create a function, or create a method, because
we're inside of a class. And I also self and I'm going to say return. So self dot, what do I want
to do here? choice underscore tax. All right. And I don't think I have to here. Let's try it. Okay,
cool. So now, it's important to add string methods to your models, not only for your convenience, own
convenience when dealing with interactive prom, but also because object representations are used
throughout Django is automatically generated admin. So later, when we go and I show you the
admin, this is actually going to be helpful there. Because then when we're reading these names, the
admin is going to be using it. All the however, we're showing it in the console right now is going
to be showing it on our admin interface, right. So like, imagine, if you create an app, and you give
it to your client, where it's like a blogging app, right, or if it's an e commerce app, you don't
want them to go to the store. And when they're trying to differentiate between items, it just
says item one, item two, item three, item four, it'd be much nicer if it says, like bicycle, or
watch or iPhone x or whatever they're selling, right? It'll be easier for them to identify.
That's essentially what we're doing right here. Note that these are normal Python methods,
let's add a custom method just for demonstration. So they're adding a new method here. So we're
going to do that I'm going to go into my models, and we will import date time at the top. And
then we're also going to import timezone. Oops, right underneath this guy. And we will add
this method under a question. Okay. Okay, so was published recently is a method in the
question class, so you can do like q dance was published recently. And it will tell you what it's
going to do is going to basically tell you true or false, okay, so I think what it's checking for is
like if it was published within one day, or later than 24 hours, let's see what they say. No, the
addition of import and to and from Django, import timezone. to reference Python standard date time
module on Django is timezone related utilities, respectively. save these changes and start a new
Python interactive shell by running Python managed up py shell again. Now, because we didn't make any
changes to the models, we just added new methods, we don't have to migrate this to our database, all
we need to do just like exit out of this shell and just like, come to it again, I'm gonna do exit
open closed paren. And I'm just gonna do Python manage that py shell again. And then let's see
if we can get that command from poles or models. So basically, from this file polls dot models,
I'm importing this class question and this model choice model, both are models, classes, whatever.
And make sure our string our addition is working. Okay, so now we're going to try to do the same
thing except this time, it's not going to show us question whatever is gonna actually show us the
text of each question. So there you go. What's up, what's new, what's poppin Okay, much easier for
To see this Okay, so again think of it like if you had a fighter database instead of it saying
fighter one fighter to fighter three, it show it to as like can write you and like say got Django
provides a rich database lookup API is entirely driven by keyword arguments. Okay, so you can do
something like, hey, I want you to filter by where the ID is one. So give me that specific question
only, or I can say filter by 82. And it'll give me the question that has ID of two, okay? Or I can
filter by question tax that says new inside of it, or what's new inside of it? Just like it's showing
me here, like, if so let's try this one. Okay. So question text starts with what? Okay, so let's
see. So far, all of these start with a what? So it's going to show us all three. But what if I do
instead of starts with I say contains? And I say, often? Okay, there's only one question
that contains that, okay, then later, we can provide a front end to our client where
you can like, in the search bar, type it in, but on the back end, we're using this contains
method to find the exact thing that you need, and then return it as a response from our HTML
file. Get the question that was published this year. Okay. So let's get the question as published
this year, we're gonna do this. We're gonna say current year is timezone. Now that year, so
that's going to get basically 2018. Right? If I do current year, it'll say 2018. And question
that objects I get, where the publication date, year is the current year. Okay. So let's do that.
Get returned more than one question or turn three. So because we have multiple questions, instead of
one, RS is going to be different than theirs very slightly. Okay. So for ours, since it matches
all of them and gets like Yo, what's going on, I'm matching all of them. So but nothing to worry
about, it's still working for us. If you request an ID that doesn't doesn't exist, it will raise
an exception. So for us, we do have ID two, so it won't raise an exception. But like, let's say
that we try to find something with an ID of four, or five. Sorry, we have to do dot get is going to
raise an exception, okay. Also, for this, let's try. So what would happen if instead of dot get
we use filter? Would we get an error? Or would we get something in return, we would get something in
return, which is like, all of these that match it. Okay? So the difference between filter is like,
return everything that matches and get is like get one. And if more than one match, then like
throwing an error or something like that. Okay, so look up by a primary key is the most common use
case. So Django provides a shortcut for a primary key lookups a falling question. The following is
identical to questions that objects dot get ID, so PK, which is a primary key. Okay, so every
model will have a primary key. So for example, question we'll have a primary key choice, we'll
have a primary Kanda think about this is like, let's say you have a database with people in it
right? or employee names. But what if you have two john smith employees, right out of 100? employees?
Or what if you have two Apple watches in your ecommerce store that you're selling, that are the
same name? Or the two people that have the same name? How are you going to differentiate? What
if they have the same email address or whatever, right? So you need one thing that's always always
always always unique. So if you can't rely on their first name, last name, or email address,
or whatever else, one thing you can always rely on is a primary key. It could be an automatically
generated key from Python and could be like random words or whatever, right? Django will handle
the primary keys for you Everything will have a primary key even if it doesn't show it to you
on the back end. This way, you can always find, you know, the unique way of referring to
something, okay. All right. So let's go here saying that makes sure our custom method
worked. So it says cute dogs that get PK one, okay, so basically what I'm going to do is go
here and say hey, Get me the object where the primary key is one and save it as Q. And now I'm
going to ask if q was published recently. Okay, and it says true. Okay, cool. So that's the result
we got. Give the question question a couple of choices. The create call constructs a new choice
object does insert statement as the choices set available choice and returns a new choice
object. Django creates a set to hold other side of foreign key relation questions for which can
be accessed via the API. Alright, so we're gonna do this guy again. If you haven't done so already,
display any choices from the related objects set, so we don't have any choices so far. Okay. We're
right now basically voting for questions kind of like you can upvote comments on YouTube. So
now we're going to create three choices. So cue that choice that create. So we're going to
take a question, which is our first question, which was like, what's up? And we're going to
create choice taxes equal to not much with zero votes. Okay, and you can see choice has a field
called votes, and then it has choice tax. So our first answer to that question, what's up is not
much. But we're saying like, Look, it only has zero votes. Okay. Okay. And now we're going
to create another choice, but called the sky, what's up the sky? I mean, I guess that's kind of
funny. I say the ceiling. And then here's another one that is, and we're going to store this one
actually. As see, Oh, okay. There we go. Okay, so now choice objects have API access to their
related question objects, because then if I do see that question. So even though I've created this
model from choice, you know, you'd be looking, I be like, hey, how does it have access to the
specific question like, how did it access this field? Here's how I did it. Because we're saying,
in this question, go to the foreign key, and the foreign key is this model over here. When I do
choice question, it'll go and get the question from up there. That's essentially what it's doing.
Okay. So that's what, when I do see that question, that's what's happening. It's referencing and
getting me back this object. Okay. And vice versa. So you can also reference from question you could
reference choice. Question objects had access to choice objects, okay. So they both have access to
each other kind of like, you can have a book and, you know, like, who was the author of this book.
So that relation goes to the author. And then you can say, like, this author has which books
and it can relate back to the books. Alright, so now we're going to see how many choices we
have. And so we have not much is one choice, the other one we have is the sky. And then the
other choice that we have is just hacking again, all of these have zero votes, as we see right
here. And we're gonna say q dot choice underscore set counts. So this is just a count that there
are actually three choices. The API automatically follows relationships as far as you need us double
underscores to separate relationships. This works as many levels deep as you want. There's no
limit, find all choices for any questions whose publication date is in this year, we're using
the current year variable we created above, okay. So I can say choice that objects or
filter, question. Double underscore means like, you are kind of going backwards. So we're saying
question, and then we're going publication date. Okay, so actually, we're going this question
here, and then we're going to publication date, and then checking the year getting the year of
that publication date. Okay. So let's try that right over here. So it's going to get us all the
way questions that are from this current year. So it should get us all three of these. Let's
delete one of the choices use delete for that. So now what I can say is, I can get the question
that starts with just hacking. Right? And how do I do that? I say cue that choice set da filter by
where choice text starts with just hacking. Okay, so it's only going to get one question that
has just hacking in there. And if I do see, I'll show you which one it is. And now to
deleted all I do is see dot delete. Again, I'm copy pasting, copying and pasting for time,
purposes, saving time, but for yourself, like take the time to actually write all of this out,
because it's very, very helpful for you. So now that I deleted, it showed me that it's deleted.
And if we actually check again, right, it'll only show us these two choices right here. Okay. Now,
we're going to get into a pretty exciting part, which is introducing the Django admin and we're
actually going to just touch on it a little bit. And let's get started. This is a super cool
part. philosophies of generating admin sites for your staff or clients to add, change and delete
content is tedious work that doesn't require much creativity, okay? is usually like a pretty rinse
and repeat process. It's frustrating, it's boring. You can make mistakes, it takes a lot of time, and
development, and which means like, it'll cost your client a lot. And it slows down your development
speed. For that reason, Django entirely automates creation of admin interfaces for models. Okay,
so let's check it out. The admin isn't intended intended to be used by site visitors, it's for
site managers. Okay. So now we're going to create an admin user, I'm going to do Python, manage
that py create. So we're going to exit out of this and do Python, manage that py, create super user.
And I'll leave this blank, I'll use this email. And even though it's not gonna show you anything
here, it's still typing in your password. So don't worry about that. Okay, so you can put in whatever
as your email, whatever is your username. And now the final step is to answer enter your password
I have. And now it says start the development server. So we're going to do just that. I'm going
to start the development server, we're going to go to Chrome, we're going to go to our local app on
127 dot 0.01, colon 8000 port, instead of polls, I'm actually going to go to admin. And when I go
to admin, look, it brought up this nice interface that you and I did not make, we didn't make this
beautiful looking form, where when you hover over log in it, like turns dark and looks good. And
we didn't add functionality that add security, right? We didn't add this thing where passwords
automatically looks like dots so nobody can see it. All of this keep in mind is just automatically
generated. When I click login, boom, here's the administrator interface. Okay, so as the admin,
you can change your password, you can log out, you can check what who are the users. So here's
one user, you can like, go into this user and like delete this user, or change the permissions of
this user, right? So you can go in and like boom, it's not a super user anymore, or is not a staff
anymore. It's not active anymore. Or you can go in here and like change all kinds of permissions,
like can delete choice can add a question but cannot like delete a question can change a
session, but cannot delete a content type, you know, you can get like as specific with it
as you want. And this is just for the model that we have registered new users. But imagine later
when if we register our choice model and whatever, those will all show up right over here. And any
recent actions that you do actually show up on the right hand side. So imagine like somebody deleted
something, you're like, what the hell happened, like, one part of our app or this website is
now broken? Well, if you go into recent actions, you'll see what took place and exactly who did
it and who to hold responsible for that. I think that's pretty cool. Right and it comes built in
right out of the gate. That's one of the reasons why Django is such a powerful tool. And it fosters
productivity and effectiveness. I believe over any other framework, right. And their tagline, which
is awesome. It's for Django is for perfectionist with deadlines. That's what I believe in to
like, if I have to put a project together, and I'm doing something solo, I'm going
Django, all day baby. But you know, if you're working on some long term project, you
know, you're going to be doing for a long time, and nothing else really matters, then yeah, you
can choose whatever you want. But I like speed, I like productivity, I like to take my ideas from
my head and launch them online fast. Alright, with that said, let's go back and see what
they're saying. So we go to our admin, enter the admin site. And now it says, make
the poll app modifiable in the admin. How do we do that? We're going to take these three
lines of code. So I'm going to go into my polls slash admin. And this line is already added.
So I'm not going to add it in from dot models, import question. Okay. So basically, what I'm
saying is from this directory, get the models, so right here. And import the class question from
the models. Okay, so import the question model. And then I'm going to say, registered that model
inside of admin. So check out what happens. Okay, this is super, super cool. Check it out. I'm
gonna hit save. And let's go back to our app. And let's hit refresh. And look at that. It's
here. That questions model is the one we made, it shows under polls, questions, and you can see
all of those questions. What's poppin? What's new, you can go in and you can change the text. So I
can change it to like, what's cracking? Right, I can hit save. And now it's changed. And if I
go to my, if I start Python managed up py shell. From polls, dot models, import question. Question
objects. All right, look, it says what's cracking. So what we actually changed from the GUI interface
with our mouse, and our keyboard is now showing up in our database in our local database, SQL lite
database actually being stored on our computer, this database is not online yet. So pretty freakin
cool, right? How quickly and how effectively works. So I'm going to exit out of this, I'm going
to run my server again. And we're going to go back to the app refresh. Cool. And like, let's see
what they're saying. Now that we have registered question, Django knows that it should be displayed
on the admin index page. And it is right and I showed it to you. And we went inside of it. And
we saw question tax and we saw date published and we can actually change the date published
and everything. Now things to note here, the form is automatically generated from the question
model. So this form is automatically generated, we didn't generate anything, the different model
field types, date, time field and car field. So remember, we had one of the models as a date
time field, and the other one is car field. And you can see where it says date published
load Date field, right? And for question, text is just a straight up character field,
or what you know, in Python to be as a string. These correspond to the appropriate HTML input
widget, each type of field knows how to display itself in the Django admin. Pretty cool. Each day
time field gets free JavaScript shortcuts, whoo, free JavaScript shortcuts. That's awesome, too.
Normally, you'd have to write JavaScript for all this stuff, but like, look at this, okay, so let's
say I go to what's cracking, and I click here, boom, look at this beautiful date time picker
thing opens up, and you could pick today, or you could pick another date, and like automatically
pick it and you could pick the time. And that's cool. This is this is something you'd have to
write a lot of manual JavaScript for, that's automatically written for you. Dates get it today,
shortcut and calendar pop up and times get a now shortcut and convenient pop up that lists commonly
entered times. The bottom part of the page gives you a couple of options, right? So save saves
changes and returns the change list page for this type of object. So you can do save, or you can do
save and continue editing. So continue editing the same page or you can just save and add another
add a new question. Right. Or you can do delete, which displays a delete confirmation page. So
check this out, okay? Normally when you hit, you have to add all this functionality. Plus
when you hit delete, you have to then remember to add a confirmation thing to it. And they have it
automatically. So if I hit delete, it'll be like, are you sure you want to delete the question?
what's cracking? All of the following related items will be deleted. Questions, one. So only one
question and objects. What's cracking? You can say yes, I'm sure or no, take me back. Now notice,
it's showing the question is what's cracking? That's because of your string method that you
added your str method. If you did not have that, it would not show like what's cracking, it was
show like question one. And you just have to use your memory to remember that. I'm going to say
no, take me back, and it'll take me back. Okay. Cool. Let's go back. Let's see what they're saying
here. And then if the value of the date published doesn't match the time you create it, it probably
means you forgot to set the time. We can also set the current timezone, right. So that's not a big
deal. If I go in history here, it says I changed at 3am. It's not 3am right now. So that means
like, I need to go inside of my settings and in my timezone and change what my timezone is.
So for example, I think there's like, America slash Los Angeles, something like that. Oh,
actually work sweet. for yourself, just look up like timezone Django timezone settings, and then
find yours and put that in for me, I put this in, and it fixed my time instantly, right. Okay, so
yeah, I essentially that's it for part two. We're gonna jump into part three. And we're gonna get
started. So if you haven't already open up, Adam, go to where you created your mind site project,
right? For me, it was in GitHub, my site, I'm going to click Open. And I'm going to say,
whatever open and recover state. Cool. And here it is. And then if I do command, shift P and type
in Terminal, my terminal pops up. But uh, bam, and also make sure to do source activate my site.
And we are good. Okay, so writing your first Django app, part three. So what they're talking
about here, is they're saying, okay, like, Look, you have everything in Jango is essentially
called a view. Okay? So for example, if you have a blog homepage, that's a view, if you have
the ability to comment, like a comment action, right? That's considered a view. If you click
on a blog post, and it shows you the details we refer to that is a detail page, but that's still
part of the view. That's essentially what they're saying right over here. Another example of this
is like, let's say I take you to Instagram. So let's say I click on clever kasi, right? This is
essentially for Instagram. And let me just plug my Instagram here to go follow me if you aren't
already. Because awesome. And if you go here, right, like, Look, this is the home page for all
my posts, okay, this would be considered the home page view. If I click into it, that's considered
a detail view, because it's only showing that one particular post, okay, if I click here, that's
a comment action, which is, you know, you can work that into the views. So just wanted to show
you that. So you understand where all of this is coming from. Now, we come over here, and that's
now they're saying that in our poll application, we're essentially going to have an index page in
our views. So this is going to display the latest few questions. We're going to have a detail page,
which is going to display a tax with no results, but with a form to vote. So when you click so
like, you come in you a bunch of questions, you click on a question, and then boom, it has like
ability to vote it up and down. Okay, I assume. And we have a question results page. So it's going
to display the result for a particular question. How did that question do? How many votes it got?
And then we have vote action. So handles voting for a particular choice in a particular question.
Okay, cool. All right. So now, we kind of know that we're going to be creating like these things.
Okay. We're going to be creating an index homepage detail and results. And also what they're saying
over on this part. Is it saying like, Hey, man, have you ever seen really ugly URLs like this?
Well, don't worry, because in Django, you can make them really beautiful. So you can Have them
like this instead, like john smith comm slash news archives slash 2018 slash two or slash February,
whatever. And you can make them look really nice. How does it work? It works off of URL concepts or
your current URL configuration mapping, okay? So you map URL patterns to views. So somebody goes
to this URL, it knows which view to run. Alright, so now we're going to write more views. Okay,
so we're going to write these guys here. Again, I'm just going to copy it and talk about it for
you, I encourage you to type it all out and walk through it. Okay, I'm just going to highlight the
main parts, I'm going to go in my poll slash views that p y. So in polls, I'm going to go inside
of views are actually we're going to leave the index for now. paste it here. Okay. So now we
got detail, we got results, and we got vote. Did everything always takes in a request object? Okay,
a request is passed whenever you do anything. I'm not going to touch on too much right now. But this
is a first parameter you kind of always put in. And then as your second parameter, we're putting
in the specific question ID this way, we can look up that particular question from the database.
So let's say you wanted to look up a blog post, right? So you have multiple blog posts, you want
to be able to look up a specific one? Well, we're going to use ID for that. And in this case, our
ID is our primary key. And that will allow us to look up that unique thing, or in Instagrams case,
it allowed us to look up that unique post. Okay, cool. Now, what we want to do is wire these
new views into the polls dot URLs module, but adding the following path calls, okay, so
that's what it's showing here. I'm going to call, I'm going to copy this and I'm going to paste it
into our polls slash URLs up here. Go slash URLs and paste it here. Alright, so what does this
mean? If you just go to slash polls, right, so john smith comm slash polls, it's going to run
this thing is going to match the empty pattern after polls. And then it's going to run the views
dot index function, okay? If you go to polls, slash, if you want to go to something like
polls, slash five, or Instagram post slash, whatever your post is, right? If you want to
build to do that, you want a pattern that can match that, okay. So if I put in 20, it shouldn't
break. If I put in eight, it shouldn't break, it should always be matched. And so how we can
do that is we basically do this thing with angle brackets and int, colon, question underscore
ID. And this can dynamically match whatever pattern you put in. And another beautiful
thing, you guys, usually for URL mapping, you have to deal with ugly regular expressions,
except for the latest Django, you don't have to worry about regular expressions anymore. So
for example, let's say you wanted to match this particular pattern. Well, you can put this
in, and if somebody puts in a five here, right, they'll automatically know that it's an integer
and work. If they put in something else, it might freak out. Okay? So it's really smart. And then
it says, Hey, if somebody goes to a URL like this automatically takes them to the detail view. And
if somebody goes to a URL that ends in a results, like this, then, which is essentially what you're
saying here, hey, any number, followed by results. Take them to the results, one, and any number
followed by the word vote, take them to the vote, view. Cool. And let's see what happened. So I'm
going to run I'm going to do Python, manage that py run server. Cool. And I will open up my Chrome.
And we will go to this guy over here. Okay, so now we're getting an error is because we actually have
to go to that particular URL. So in this case, let's go to slash polls, and it should run our
index function. So I'm going to do slash polls, boom, it ran our index function. What
does our index function say? Let's go to our views. And that's what it says, Hello,
world, you're at the polls index. Perfect. Well, what if somebody goes to polls slash five or polls
slash 193? What happens then? It'll take us to the detail function, and what does the detail function
say? It says, you're looking at question number. What the question ID cool. So let's try and
let's see what happens. I'm gonna do 193. Okay, so the cool thing here that's happening is that
you're able to take what's in the URL and you're able to pass it down to your HTML. So right here
that 193 right. If I make it like some other crazy number pass that down here, right? So now we're
able to actually take in arguments from our URL and use them in our code. What if I said something
like this, it'll say, hey, that pattern actually is not matched. So that's exactly what we want
it. If you don't put in a number here, it should automatically detect it. Now, if you want to go
to something like slash poll slash number slash results, what do you do? Okay, so let's say I have
this number, and I go to results, just like that. And now, it should say something like, you're
looking at the results of question, followed by whatever it is. Okay? So you're looking at the
results of question, right? Or question two. And then if you go and try to do this thing with vote,
you're gonna get the same thing. So if I go to my URLs, it says, hey, go to slash polls slash number
slash vote. So we're going to do slash polls slash numbers slash votes. And I hit Enter, and it
says, you're voting on question two, perfect. That's exactly what we should be getting here.
And it's looking great. All right. So it's saying, hey, like, take a look at this in your browser,
and it will display the placeholders? And that's exactly what it did. And how does it work? Well,
detail our function that we have, will take in a request object followed by the question ID. So
when we pass in the question ID to be 193. Right, this part became 193. And this part is just that
request object. So what they have here? Again, if you're confused about objects, and what the
hell is going on, it's not completely necessary, but you should look at some object oriented
programming stuff. Okay. And I do have a course on object oriented programming, then you could
comment on it if you're interested. Alright, so the question ID is equal 34 comes from this
thing, and I've explained that to you already, when you put that in the URL, this dynamically
actually pulls it out. And once it dynamically pulls that out, because you see it says,
here, it says, question ID question ID, that's where it's actually pulling it from. Okay.
And that's essentially it. And then it says, Hey, you don't need to do ugly things like latest
dot html, because it's not necessary. And it's apparently silly. Okay, so don't do it. And you
should write views that actually do something. And here, they're saying, hey, look, each view
is responsible for doing one of two things, either as your return what it's supposed to return
or give you like a 404. And then the rest is up to you. So, you know, basically, you can have a
view, or it can read records from a database. So meaning reading records, reading posts, from
a database, Instagram posts, Facebook posts, or it can generate PDF files, or output XML or
create a zip file on the fly, anything you want. And pretty much using whatever Python libraries
you want, because Django is 100% Python, so you have full Python power. And then all Django wants
is that HTTP response, okay. So you can return it as a string, you can return it, you have to return
it as some kind of an HTTP response. or throw an exception. Okay, so now, here's what they're
doing. They're like, Alright, we're going to do something cool. Well, we're gonna do is we're
gonna take like, all of the questions you have, we're going to order it by the publication date,
and then show the top five most recent ones. Okay, how are they doing that? Well, I'm going to copy
this, and then we're going to play around with it. Okay. So we're going to go back to our thing,
and what do they have here from dot models, import questions, and they're in our poll slash views.
Okay, so this is one thing that we need to do from dot models, import question, because we don't
have that. So we're going to paste it in here. And then they want us to redefine our index. Okay. So
we're going to do just that I'm going to change my definition of what my index function is.
Alright. So how is this working? Well, question dot question that objects are ordered by. And what
this thing does, is it'll take all your questions and order it by something. So in our model, if
you look, we have this thing, publication date, so pub underscore date. So we're going to order
it by publication date. Now what we're doing with this minus sign is we're saying in the reverse
order, okay. So instead of the oldest publication dates and showing us the oldest, we wanted to show
it in a descending order. So we wanted to show us the recent ones first, and then what we're doing
is that we're just and So this will return to us a list, okay? And then you can index a list in
Python by doing this. And we're just saying, Give us the first five. So from zero, up to,
but not including five. So 01234, that's five, okay. And then as output, we're saying, hey, join
all of them all of the questions by a comma. Okay? So if you want to know a little bit more about,
like how the Python is working in there. So here, we're doing a list comprehension. And you can
read more about list comprehensions. If you don't know what that is, it's not too important.
And it's just a cool way of writing this, you know, instead of multiple lines is writing one
line. And we're just saying, for each question, give us its text. That's all we're saying.
And then we're saying join it all by commas. So that's how it's going to output it. So it's
going to return to us pretty much a string, okay? And then we want to return that. Okay, as our
outputs originally HTTP response output. That's it. So now, let's take a look at it. So I'm going
to save it and we're going to go to our thing, and we'll try to go to our index, and where's
our index? It's just that slash polls. Okay, that should trigger our index. And let's see
what happens. So I hit Enter. And it shows me all my questions. If you remember, I created three
questions, what's cracking, what's new, what's up, and it's showing us with separated by a comma, I
could do show it to us separated by three stars, if I refresh, it separates it by three stars, you
could separate it by an image, whatever you want, you know, this is just pure Python. Okay, so
that's essentially it. But there's something wrong here. And the thing that's actually wrong
here is like, Look, you're not gonna have your toilet and your refrigerator in the same room,
right, you're muddying the water, just like that. You don't want to have your HTML code and your
Python in the same place, we want to kind of separate it out. So right now, the design of our
page is in the same place that handles our logic, okay, so what we want to do is handle our logic
by pure Python in one place, and all our HTML. And the design of the page should be outside of
this logic, okay. So we want to create something for that. So what we're going to do, and what
this tutorial tells us to do, is inside polls, you want to create a new folder, and you want to
call this folder templates. This is important the case sensitivity of this is important as well as
the name. So if you mess up the name, or you put a typo, you're going to kind of get messed up here.
also pay attention to the order of all this, okay? It's under my site. So under polls, you're going
to have templates. And then inside of templates, you want to create a new folder, and you want
to call it polls. All right. And inside of this is where you're gonna throw all your HTML file.
So we're gonna create, we're gonna create a new file in here, and we're gonna call it index dot
HTML. Okay, so just in slow motion for you, polls, templates, polls, index. Okay. So essentially,
it's like polls, templates, polls, index like that. Alright, let's go back to our tutorial.
And that's what it's saying. It's saying that, hey, Django will automatically look for it
and find these templates. And essentially, to Django, the path will look like polls
slash index HTML, because of how Django works and looks for these. And you can override
it and do all kinds of advanced stuff, you know, if you want to read more into that, we're
gonna just kind of keep it a little bit basic, so everybody can follow. Alright, and now we're
going to put the following code into into that template. So it's telling us which file to
put that code. And so I'm just going to hit this button, copy this code. And we're going
to go into our index HTML, and I will paste it right over here. Okay, what is this code saying?
It's saying, hey, if there are any questions, then I want you to create an unordered list. Okay,
that's what a ul tag is in HTML. And then what I want you to say is for a question and so for any
questions, I want you to put it as like a bullet point and show that question, okay. And link to
that particular question. Otherwise, say that there are no polls available. So if we didn't have
any questions at all, Elsa, no polls available, and then end The if statement. Okay, so we're
starting our for loop here. We're ending it here. We start our if statement here. And then we have
our l statement here. And we have our end if here. Alright, so that's cool. Now we want to make sure
that we actually link to this index dot HTML file. How are we going to do that? Here's how. Now let's
update our index view in polls slash views that py to use the template. Okay, so we're going to
do just that. And also, let's update our index function just a little bit. So here's a few lines
that we're adding. Let's go back to our views. And we will see the latest question. We'll keep that
and we'll just paste this in here. All right, save. So what's going on? We're still getting
those remotes recent five questions. But that's what latest question list is going to become. And
if you don't have five questions, they'll pick the top three or top or the recent most for, okay,
something like that. And then what we're doing is we're loading that template poll slash index HTML.
Okay, so we're using loader, arm. And then there's something called context dictionary in Django. And
what you can do is you can pass from the backend server side, pass this to your front ends, your
HTML code, it'll know about it. Okay. So if I go back to our templates, my index dot HTML, how
is it getting access to this variable, latest question list? Well, we're actually passing it
in our context. All right, that's, that's what's going on. And then we're saying, as HTTP response
template dot render, we're saying, hey, send that context with that request and send it over to
the HTML file. So it sends all that over to the HTML file, and then our HTML file has access
to that latest question, okay. And this weird stuff you're seeing here with this with a percent
sign, squiggly bracket, that's Django templating. Engine. Okay. So it's basically HTML with a little
Django pizzazz. Cool. And so now they're like, Hey, this is such a common step to load a
template, and then to do template dot render, that there, they made a shortcut for it, which is just
render. So how can you use that? Like this? Okay, so basically, you can remove this line, you don't
need this line anymore. And thanks to this line at the top from Django, shortcuts, import render,
which you should have, we're going to use this render, and how are we going to do it, we can just
replace all of this. And we can say render. The first argument is request, okay. And then after
that, the path to that index file, so polls slash index dot HTML, just like that, followed by the
context dictionary. So in this case, we're just calling it context. Okay. Sometimes what I like
to call this is stuff for front end, alright, just to keep it consistent. And just so you
know, the thing that you're accessing on the back end is not this guy. It's a dictionary context,
dictionary key. So it's actually this string. All right. And that will give you back this guy. Okay,
so know that once you've done all this in views, we no longer need to import loader, blah, blah,
blah. Exactly. That's what we did. And now they're going to show us how to raise a 404 error. All
right, so what happens if it doesn't exist? So let's tackle the question detail view. The page
that displays the question tax for a given poll, here's the view. So in polls slash views that
py we're gonna do is we're gonna from Django HTTP import http 404. So since we're already
using Django dot HTTP to import HTTP response, we're also going to say http 404. Okay, just
like that, we're going to save it. And then we're going to come back. And now it wants us to make
changes to our detail view. And it's saying, hey, turn it into this. So let's turn it into that. And
I'm going to save it. So try accept blocks, all it does is if there's an error, try except blocks
will catch it. Okay. Try accept block, it is pretty much the same thing as if then condition,
except that if you're running into some kind of crazy error tracks, that blocks will catch it and
still run. For example, if you divided a number by zero in Python, your code will just freaking
crash, right? It'll give you this red blob, your Apple crash, whatever. But if you run a try
accept block that says, if you get a zero division error, then Just pass, you'll not get that error.
I'll just pass it. Okay. So what we're saying is we're saying try to get that particular that one
specific question. Okay. So we're saying, we're getting that question ID and we're saying get that
object that has that primary care that question ID, or right, that primary key is equal to the
question ID. So if I pass in a URL like m AP comm slash polls slash six, right, what is it going to
do? Or let's say slash two, what it'll do is pass this two in two here, that this will become two.
And the question will get the question object that has an ID of two in this case, it might be one of
my question that I think is what's new, right now? What's new question? So then this question will
become the What's New question object? And then what we do is that we just return that, okay. And
we pass it in our context dictionary, and we pass that question in here. Except if the question does
not exist, then we raise HTTP four. And we said question does not exist. Okay. Cool. Let me make
sure to delete that. That's not supposed to be there. I just added that to show you guys what's
up. Okay. The new concept here, the view raises. Yep. We'll discuss what you could put in that poll
slash detail that HTML template a bit later, but if you'd like to quickly get the above example,
working a file containing just this. Okay, so we're going to get that thing working. Okay, it's
right in here. We're going to create a new file, and we're going to call it detail dot html. And
in detail, we're just gonna put question just like that. Okay. So now we got to make it work. And
we're going to go and get our question too. Okay. So because that specific question exists, look,
it says, What's new? Now, if I change this ID to one is going to get the question that was what's
up. If I change it to three, it's going to be the what's cracking. But what happens if I change it
to four? Remember, I only created three questions. If I change it to four, it says page not found.
And look, the error throws up his question does not exist. Now, if we didn't have that, right, if
we actually don't have that, so let's go back to our views. And I'll just remove this. And I'll
just say, instead of rays, I'll just say, pass, okay, passes the equivalent of saying ignore
to Python. Let's go back and let's refresh. We're going to get this ugly error, which we
don't actually know what to do with or what it means. And it is very confusing. But when we
have this when we raise this thing, and I refresh, you see it says question does not exist. So it's
a lot easier for us to see what the problem is, is because we know it's coming from here, then
we can like start debugging and know what's going on. Okay. So that's why that particular thing is
important. Alright, let's move on along. Alright, so a shortcut. So instead of having this try
accepting or raise, we can actually do a cute shortcut that says get object or 404. And that's a
method that's in Python. In Django, it comes with it. So we'll throw that and it's in our shortcuts.
So from Django, shortcuts, import, render, and actually import get object or 404. Okay, and just
to stay consistent with them, we'll do it in this because starts with the G and starts with R. So
alphabetical orders and pep eight. Okay. Alright, so we're gonna go here, we will go to where it
says question in detail. And we're going to remove this whole thing, okay, make our life easier. And
all we're gonna do is we're gonna say, bam, right? We're gonna say, Hey, get object or 404. So that
particular question with the primary key of this, if it doesn't exist, then it'll automatically
say it doesn't exist. And then pretty much the last line, we'll keep it what it was. We'll save
this. And basically as our context dictionary, we're saying pass a question as a question. Okay.
So there are three arguments in here, request, the HTML, passive HTML file as a string, and then
a dictionary. So then we can use it on our back end. Again, in our detail, HTML, we can actually
use we can see that question. Save. And now let's try to go to it again. So I'll say four. And now
look, it says no question. No question matches the given query question, as Unlike no question
object, okay, but if I do three, it finds us and takes us to it. So this is what we mean, this
is what I mean, when I say Python is really, Django is really awesome and comes with a lot of
intelligent defaults. Whereas you don't have to write a lot of a lot of this code, right? It works
on that DRI principle, do not repeat yourself. And a lot of these things just come built in out of
the box, and it it speeds up your development time, saves you a lot of those new code lines,
because every new code line that you write, there's an additional chance for an error. So the
amount of code lines that you can reduce, the less errors you will make. Plus your code just
looks beautiful and so much more readable, right get object or 404. Instead of try that
at all. Except object dot does not exist, right? So it's confusing. Okay, let's go on.
Get object or 404. This is some advanced stuff, we're gonna skip that for now. Now it says use
the template system. So in our detail dot html, we're gonna go and I'm going to paste that there,
save it. And let's see what it's saying. Back to the detail view for our poll application. Here's
what it should look like. Okay, so now let's go to the detail. And let's see, first, let's just
see what the result is right? And then we'll talk about it, I'll hit enter. What's cracking is
showing it to me in a nicer way. Let's do two, it's showing it to me in a nicer way.
What happens if I do four? Same thing, no question matches the given query. Okay,
so what are they doing here? They take your particular question and they wrap it up in
a h1 tag in HTML, anything that's an h1 tag, will make it's called the heading one. And you can
go all the way down to heading six, heading six being the smallest heading one being the biggest
boulders. So we have an in a heading one. And then right underneath it, we say for choice in
question, dot choice underscore set dot all. So for all of the choices, as like at choices as in
particular answers, you can have to each question, right, though, those answers are the ones that
actually get an upvote. Or there's no downvote, sign up vote, show me all of those answers,
except in this case, we don't have any answers or any choices. So that's why it's not showing
those. How is it working? The template system uses dot look up syntax. So you'll do question
question tax. So we'll go into the question, and then it'll access a question or score text.
Another thing to notice if you're more advanced, if the question underscore text attribute did not
exist, it would go and try to access it as a list index. Okay, so imagine if it was like if you
did question dot zero or something like that. So you're still using dot notation. So that's
something that could trip you up later. Okay. It would have tried a list index lookup, okay. And
then method calling happens in the for loop. So this for loop method calling is happening there?
Because you know, you're doing question that choice underscore set dot all, okay. And then
it's interpret as Python code, which is cool, like right here. And it returns an iterable of
choice objects. And then we iterate over it, right. So that's why we use a for loop, and then
we iterate over it. Now. Remember, when we wrote the link to a question the poll slash index HTML,
so let's go to our polls slash index dot HTML, you can see what we did here. Right? So we said,
slash so for the links. We said slash polls slash this. Right. So let's go take a look at this page.
One more time, we're going to go right here. And I'm just going to hit pause and hit enter. So
you can see how it's showing me what's cracking, what's new, what's up to each of this. And when
you click into it, you go into the detail view, right? Kind of like when you click into a blog
post. And also under What's up, you can actually see the choices. So that's just a recent thing
we just added. Right? So how is that working? How are we linking it and how we're linking and
we're saying slash polls, slash that question ID, which matches, one of the paths in our URLs are
p y. So if I take you to my URLs, it'll match the path of this guy. And that takes you to the
detail view. And that's how we can see the detail view. So let's go back, but we're hard wiring the
URL paths this way if we have a lot of URL pads, or logic and get messed up or if we change if
we go in our URLs that py and I, I don't know, change this path to be something else, right? It
has like, it says polls here, again, followed by something else, it could like mess us up. So what
we want to do is we want to use it in a dynamic way. So that's what they're showing us here. So
they're saying, hey, replace this guy with this guy. So we're gonna do just that. Okay, so we're
gonna go back to our index HTML, and we will just do this. Okay. So now what this is saying is,
for the URL, use detail, detail as in this, that's where we're getting the name from. And
then as the argument passed in the question.id, so this question, since we're looping over it, if
you do question dot use a dot notation, it'll get you that particular questions ID. So question
ID, that's what you pass in as argument. And so then when you go to your URLs, to this question,
ID, that's what it's going to pass. Okay, that's essentially it. And I believe you should also be
able to do question underscore, ID equals that, but in this case, we're just going to keep it
like this. Okay. So no need for keyword arguments. Okay. And then in in between here. So that's what
it's going to link to, it's going to link to the detail view of that particular question. And the
text that we're generating is just from right here. So that's question dot question underscore
text. If you are confused by this, look up stuff on HTML, okay, and look up how links work in HTML.
Again, I'm not going to go into too much HTML, because that's outside the scope of this tutorial.
Okay, and that's how it's essentially working now. namespacing url names. It's basically just telling
us like, Hey, look. So let's go down over here. Let's just make sure we're not missing anything.
Okay, from the top. Okay, they're saying, if you want to change the URL to something else,
perhaps it's something like polls slash specific slash 12. So this is something that I've already
said, but but they're just reiterating here. And they're saying it like, if you change the URL,
it's still going to work now that we change it to be the dynamic way. Okay, so now we can change our
URL pattern to whatever. And it's not hardwired anymore. And now they're talking about namespacing
URL names. Okay. So this way, you want to make sure that all of your apps actually have, there's
no way for like, right now we only have the poles app, right. But what if we wanted to have more
apps inside of this, then what can happen is that if any of our HTML files name matched, so
let's say you have a polls app, and it has an index dot HTML file, right? What if you had a blog
app, and that also had an index dot HTML file, now you're gonna have a collision. So what we do
for that, that's, that's the reason why we create under templates, another folder called polls. And
if we wanted to add templates for our blogging app, that's why we would have an app called blog.
And then under that, we'd have templates and then under that, we'd have blog, and then under that
would put our HTML stuff, okay, that's the reason why we do it like that. And this way, there's
going to be no collisions. Okay. Now change your poll slash index dot HTML. So let's see what
it's saying here. So we can have our app name, app underscore named avatar name is equal to poll. So
this is in our URLs. py. So let's go right there. urls.py. And they're saying, hey, add that guy
right over here, okay. And pretty much everything else we want to just leave as is. Now change your
poll slash index dot HTML template from this to this. So in our index HTML, we're gonna go right
here, and we're gonna paste that guy. So notice the difference. All we did is we do polls equals
d polls colon detail, okay? That's really the only difference. There's no other difference. I'm
gonna save that. And this way, our URLs will never collide. And everything has a proper name spacing,
right, because right now we created a detail for our problem. What if you want to create in what
if you had an add a new app called blog, and then create details in there. You don't want it to just
be called detail because it's going to collide with the polls detail. But now because it's
polls colon detailed, then later, you could do blog colon detail, or Instagram, post colon detail
or Facebook status, colon detail. And this way, you can differentiate all of those different apps
you have within one of your Django projects. Okay. writing your first Django app, Part Four. Alright,
so we're continuing a web poll application. And we'll focus on simple processing, simple form
processing and cutting down our code. So the big things we're going to be doing is how do you add
a form, that where you can submit information to, so basically, it's going to be a form is gonna
have radio buttons, you're gonna pick your choice, you're going to click on it, and then you're gonna
be able to send that data over, that's number one big thing we're going to be doing. The second big
thing we're going to be doing is cutting down our code using something called Django is a generic
views that are super, super powerful. And it makes your code a lot more readable, and it stops you
from doing the same thing over and over again. Okay, so it makes things a lot simpler for you. It
does have a little bit of magic involved. But hey, that's what I'm here for. And I'm gonna break
it down. So let's jump right into it. Alright, so writing a simple form, I'm going to copy this
guy, and then I'm going to break it down to you, you my friend should not be copying, you're
learning this stuff. You should be writing this down line by line and going, huh? How does this
work? Ah, that's how it works. Oh, hmm. And then you should be googling it and looking it up. Okay.
For me, I know how this works. I don't want to waste my time a copy, paste it and then break it
down for you. capiche. Let's get going. Alright, so let's pop open our atom. And we will go into
our detail dot html. And we're going to put this over that. Okay. So what is going on at a higher
level? We have a for our heading one. So this is where, what the specific question is, okay, so
what's up? What's crackhead what's pop and things like that? All right. Here, this line is saying,
Hey, man, look, if there are any error messages, I just want you to freaking show them. That's all.
And this guy over here is just a form where you actually submit and vote, okay, at a high level,
that's all that's happening. Okay, now getting down more into the code level. This is pretty self
explanatory is just h1 tags is just HTML, here is a little bit of Django going on. So here we're
saying, if there are there is an error message, then show it, okay, and show it covered in strong
tags, that looks nice. And then here's where we're creating a form. So we started the form tag here
and the form tag here. The action is to go to this specific URL, so trigger this URL. So basically,
action means what the heck happens when you submit a form? Right? what's an example of a form?
You? Every almost every website has it? Okay, so you going on Instagram and logging in, you
are submitting a form you logging in on YouTube, you logging in on Facebook, you are submitting
a form, you posting a status hitting post, you are submitting a form, okay. So
that's essentially what's going on. So what we can say here for action, once
you submit a form, what should happen, okay? One thing you could do here is just type
in facebook.com. So once you submit this form, it just takes you to facebook.com. Okay, you can
certainly do that. Except in our application, what you want to do is, once somebody submits a form,
you want to send them over to some other part of your app with that information with that data. For
example, if somebody adds shoes to their cart, it then takes them to the new page with information
where they previously added shoes to their cart, and then shows the shoes and the shirt and the
tie on. proceed to checkout page. Okay, that's essentially how you use forms in real life. Okay,
so here we have it to Hey, take me to the vote. View, okay, or the vote function in our views
file. Cool. CSRF token so there's something called cross side. I forget what it fully stands for.
Let's take a look at it. They mentioned it cross site request forgery is okay. So it's a security
mechanism and All you have to do is really not to worry about it too much. All you have to do is
just add that token. Okay, so actually, that's it, that token doesn't even need an end. That's it.
This is just a line that you add, usually when you're adding Django forms unless you're using
something like crispy forms, which is, again, outside the scope of this tutorial. So that's what
this line is here. We're doing a simple for loop. Okay, the for loop goes through all the question
choices. And what are question choices? Well, remember each, so you have question, and then
one question can have multiple answers to it. Those answers are the things that get voted on. So
what we're doing now is listing out all of those answers or, or those choices. And, and, and I'll
show you right now, how al actually look Okay, so let's go ahead and check out what this looks like.
So now, we're gonna go over to our app. And let's click on what's cracking. And you can see it says
what's cracking followed by vote right underneath that. Okay. Let's go to what's up. What's up has
two choices. Remember, I had not much and the sky? Those are two possible answers. kind of funny.
I don't know which one I like more. But yeah, you could you could vote on one. And then you
could certainly hit vote, okay. Yours is not going to look as big as mine. That's because I
have it zoomed in. So you could see on my 5k, iMac retina screen, and you can pick whichever
one you want. That's it, and then you hit vote, boom. Okay, you're voting on question one, it will
redirect you to that. Cool. So that was that the radio buttons are coming from these lines, okay,
how's this working input type radio, when you do this, then it creates those radio buttons on the
side, okay. I for ID something you don't have to worry about too much. But for ID, we're just
using the built in Django templating systems for loop counter. So we'll give the id 1234. As it's
looping through. And yeah, values, just a choice that ID and Name, we're just calling a choice.
Name is very important. Once you get this on the server side, the back end, you could reference
this post data using that particular name, okay, so you're gonna be able to do something like
request, I post bracket choice. Okay, and then label for, that's just for labeling purposes.
Again, not incredibly important to what we're doing. And then we end the loop right over here.
And then right over here, we're saying this form is basically what we're saying is like, put that
Submit button, and then just call it vote. Okay, so that's why you see, you know, if I called
it something else and saved it and refresh now calls it that. So here we're saying call it
vote. And then for type, we're going to say it's a submit button. So the type which is
going to give us submit, so once you hit it, it sends that information over to the next page.
Cool, let's go back to our tutorial. Alright, so that's pretty much what is gonna explain to us,
but let's just see and make sure we're not missing anything. Right, so the value of each radio button
is associated, is associated question choices ID, the name of each radio button is choice. Yep.
That means when somebody selects one of the radio buttons and submit the form, it'll send
a post data choice, where a number is the ID of the selected choice does the basic component of
HTML forms, okay? We said the forms action to that particular URL, and we said method is equal to
post. So here's another important thing to note, this is pretty important. Whenever you're
generally submitting data, or filling out a form and sending it over, you want to use post request.
Because it's safer, and it's better. You don't want to be using GET requests when you're sending
data over because it's insecure, and you can get screwed. Okay, so simply put, as opposed to get
it's very important, because the act of submitting this form will alter data server side, whenever
you create a form that alters or data service side, use method post. This tip isn't specific.
Django is just good web development practice. For loop counter indicates how many times a four tag
has gone through its loops. Okay, I've explained this already. Since we're creating a post form, we
need to worry about cross site request forgeries and I've already gone over this as well. Okay.
And that's why we're using CSRF token. All right, now, let's go Create a Django view that handles
the submitted data and does something with it. Remember, in tutorial three, we create a URL con
for the that includes this line. So we already have this line, we don't have to add it. So if
I go to my URLs dot p y, you'll see four votes, I have this line right over here, and so should
you. Alright, now let's add the knowledge, we're gonna create a real version for our vote. So
up until now, we had functionality for our vote, but it was just dummy placeholder didn't really
do anything. Okay, so now we're gonna actually add real functionality, what are the few things
we need that we don't have? Let's see, we'll need HTTP response redirect, because we don't have
that. So we're gonna put that in. All right, we're gonna save. What else do we need? We need
from Django dot URLs, import reverse. So we're going to add that in and hit save. And then that's
essentially, essentially and then it except we're gonna have choice right here, save cool. Okay, now
we're gonna go in our vote, and we need to add all of this code. Okay, and I'll break it down for you
right about now. Okay, so what's going on here? Question? We get that particular question, or we
throw 404 error, we then get the answers for that particular question. Okay, or selected choice.
one specific choice, that's what we get. Okay? So for example, whether the choice is going to be the
sky or whether the choice is going to be something else, right? It's not going to show it to me right
now. Cuz the app is offline right now the server's close. But since we had two choices, and you
couldn't vote for this choice, or this choice, how are you going to know which one is sent? Right? So
that's what we're trying to pick here. Whichever choice you select the radio button next to that's
whose primary key we're going to be passing in. And how we get that as request our post choice
request, our post is just a dictionary, and you could index you could get pull out the key choice
from that. Okay. Just to have it make sense. Let's see, let's run this code. So what is it saying?
The problem is right here. Alright, we're gonna run this code. Cannot import name reverse http
404. Let's see where that error is coming from. Hmm. Right there, reverse, okay. And you could
still have http 404. Not a problem. All right. So let's go back to our app. Let's go to what's
up. And also, let's go back to this, save it, come back, let's refresh. This should save votes
here. Now, when I hit the sky, we're gonna see what happens. So I'm going to hit inspect here.
And our console pops up, right? We're going to go to sources. console is looking pretty insane
right now, but that's fine. I'm going to click on network. And we're gonna click vote. So we're just
voted for the sky. Okay, now in our network. Let's see if we can zoom out a little bit because it's
a little too crazy. Alright, so in our network, we can see that the request method is post, right.
And we can actually check out the response. And in this case, it says the response failed. Let's
click here, right now, when I click results, because it was sent to results, it says you're
looking at the results of question one, right? So there is a response. And now if I look in the
headers, it tells me the request method right now is get, and it tells me kind of all the things
that go along with it. Right. So let's try it out again. Let's pick another question. Not much.
And vote. Let's see what happens. So 302 found, right. Okay, so let's go here, preview response,
failed to load response data. If I go and results, it's showing me are looking at the results of
question number one, okay, so pretty much it says the same thing and it's giving my statuses What
do these mean? We're gonna break it down a little bit later. Okay. So let's go back to our tutorial
and go down. index HTML. Okay, so this is looking good, our views. It's looking fine. Cool. Now So
yeah, so basically we're selecting the specific choice from here, whatever we get, we send over
in our request. And then we throw an accept choice that we throw an exception here, okay? And we
also check for if like the choice does not exist, or if there's an here. And in the case that the
choice does not exist, we return polls slash detail dot html, we render that and we return
that question object. And for error message, we say that you didn't select a choice, okay? So
if you somehow selected, you know, nothing. And otherwise, if we have selected it, and we haven't
ran into this issue, we want to say is for that particular choice, we want to upload it by one.
So we're in incrementing, the vote count by one, we want to save it. And then we redirect. Okay.
So we're going to go into more depth of that. But let's just check this part out one more time.
Refresh. Let's hit inspect. Let's go to network. Let's select this guy, let's click vote. So you
can see, okay, so that's that's exactly what I needed here. So a little hard to see though.
So you can see when I scroll all the way down, that it actually pulls out the form data. And
it's telling me that the choice I selected was the second choice, right? That's an important
part. And it's also has a CSRF middleware token, which, remember we did CSRF underscore token,
that's where it's generating now from, but the choice is the most important one. So whether it
was choice one or choice two, and we're picking this based on the choice ID, okay. So that's
essentially what's happening. Now, if I go back, and I pick Not much, and I vote, and when I
go back up to vote, and I go all the way down, you'll see that it's showing me choice one, right.
So that's the thing that we're actually pulling out. So this will essentially turn to a one or a
two. That's what I was trying to get at earlier, but it was just my screws too big. So it was hard
for me to show it. But that's what gets selected here. And once this evaluates to something like
a one or something like a two, this whole thing evaluates to that specific question object.
And then we up voted, and then we save it, and then we redirect. Okay? The reason why you
so when you're done with all of this, you don't want to say, hey, go back to the home page, or
you don't want to just say like render the home page. Because if the user refreshes, it will keep
submitting that data over and over again. So like, imagine, right, if you were about to pay for
your credit card, and you buy like, whatever, right? You buy shoes, or you buy grocery. If you
refresh, like something happens during half of it, then it gets submitted. But then you go back
and you refresh, or you resubmit. It shouldn't let you resubmit and pay again, right? Every
time you refresh, and then all of a sudden, you're charged like $300? Or what if you were on
an online trading app, and you just put down like $3,000 for Bitcoin. And then you refresh, or you
go back and forward a page and it reads a mess. 3000 $3,000. Again, you're going to run out of
money pretty fast, right? $9,000 like that. So it's a pretty serious issue. So what you want to
do instead is redirect This prevents data from being posted twice if a user hits the Back button,
okay. There's a better way to do redirect, which I think they'll show us later. But it's essentially
I think, from shortcuts, you can pull out redirect and just call redirect, and it's much simpler.
But they do it this way. Should you be response, redirect, reverse and then take me to the results
view, right. So it takes you back to this results view. And for argument it just passes in the
question ID cool. So that's looking good. Now let's play around with it and let's just check out
what happened so I've already voted for like one or two questions multiple times. Let's see what's
going on on our database. I'm going to go in Python manage that py shell so we're gonna do is
from polls dot models. I'm an import choice. And I'm also going to do from polls dot models, import
question. Question dot objects, dot get Let's say we want to get our first question or what's up
question. And we're going to save this question as like q or something. And now what I'll do is
I'll do Q, that choice underscore set that all. Now show me all the choices or answers for it.
And then I'll pull out the, the sky one. And then for the sky one, we can see it's vote count. In
models, I forget what is voters votes. So you can see that it has two votes. And then the other 1/3
one, it also has two votes. So it's a tie. Okay, so both have two votes. So you see that what
we're doing on our front end, and we're voting, it's actually being counted here, okay. Usually
where it says choice underscore set, that's kind of weird. So how you want to say it is like cute
choices. And, again, like I've mentioned in our for, at the end of our first video, like if you
want to change that, I'm not going to change it now just to stay consistent with Django, official
docs. But essentially, like right in here, right, right in the top, we can actually write something
called related underscore name, and then fix this issue, like right there. call it something like
related underscore name, and give it choice says, okay, something like that. But we're not going
to do it right. Now, we're going to stick to a Django because otherwise, I'll have to make
migrations and things like that. Everything is fine. For now. I'm going to exit out of this. And
I will just do Python, manage that py run server, and just go back to using our regular app. Cool.
All right. So now let's see what they want us to do. So that's all good. That's working. Alright,
let's see what they're saying here. requests are post is a dictionary like object lets you access
submitted data by key name. Yep. So that's how we, we use the choice key name. requests that post
values are always strings. Cool. Note that Django also provides request I get that's by default,
that's there. But we're explicitly using requests our posts and our code to ensure the data is
only altered via post call. It will raise a cure if choice wasn't provided in post data, the
above code checks for key error right over here. And redisplay is the question form with an error
message if choice isn't given. After incrementing, the choice count the code returns an HTTP
response redirect rather than a normal redirect. This redirect takes a single argument the URL to
which the user will be redirected to the following point for how we construct the URL in this case.
And you should always return an HTTP response redirect after successfully dealing with post
Okay, we're using reverse function constructor, this function helps avoid having to hard code a
URL in the view function. It is given the name of the view that we want to pass control to and the
variable portion of the URL pattern that points to that view. Cool. So right here. Now after somebody
votes in a question, the vote view redirects to the results page for the question. Let's write
that view. So now, it should point us back to the results, and we're going to write it okay. So here
is what it should be looking like, let's check our results. Pop that bad boy, whoops, pop that boy
right in here. And we just say get that particular question. or otherwise, throw four or four. And
once you get it, take me to. And once you get that question, take me to results dot html. So you can
already see there's some similarities, right? Like here, there's a similarity and here's there's a
similarity. Both of these have to do with getting that one particular question. So think of it like
you're getting the result detail view for both of them. But in one, you're sending me to detail that
HTML and the other one you're selling, sending me two results, that HTML, okay. And we're gonna kind
of address this issue of like our code being a little bit repeated. This is almost exactly the
same as a detail View from tutorial three. The only difference is the template name. We'll fix
this redundancy later. So they mentioned that. Now let's create a poll slash read zoals dot html.
So we're going to go in and create a new file, I'm going to call it results dot html just like
that. I'll paste it here. And we'll go to our app. And we'll vote for the sky. And then it'll take
us to the results of what's up and look at that now much says two votes and the sky. three votes,
vote again. And then it takes me back to the vote. And I'll vote for not much. All right, so it's
coming out pretty cool. So far. All right, is this is exciting, guys. This is exciting. So now, what
is this code saying, Let's read our code who just added header unordered list unordered list, the
loop is saying go through all of the choices, or all of the answers. I don't know why they call it
choice, I just think is a bad name. And get that choices choice text, put two dashes in between it.
So for example, this would turn this whole thing would turn into like the sky or not much, followed
by the number of votes, followed by it saying vote, choice out votes, pluralized. Right. So what
this is doing is it's either gonna put an S here or not. So for example, let's go here. So if you
only had one vote, it wouldn't this would turn into nothing. And if you had multiple votes, it
would turn into it would put an S here. Okay, so it's a pretty cool way of pluralizing something.
But you're doing choice dot votes. So this will evaluate to like, let's say three, and then you're
piping it over to pluraleyes. And then pluraleyes, will be like, hey, yes, you should pluraleyes and
put an S here. And then I'll put like an S like that. Okay. Cool. With that said, That ends a for
loop. So you're doing not too much here. And then what you say is like, Hey, you want to vote again?
And how you how you're doing that is you're just providing a link to the tax vote again. And it'll
essentially take you to the detail view of that particular question. Okay. So if I hit vote again,
it takes me to the detail view of that question, what's up, not much vote, it takes me to the
results view. If I hit vote again, it takes me to detail view, click here takes me to the
results view. So this app is starting to have some functionality again. So again, that's pretty cool.
Let's go here. Let's check out now go to polls slash one in your browser and vote in the question
we did. It gets updated each time you vote if you submit the form without having chosen a choice,
you should see the error message. Okay, so let's see if we can try to do that. Let's hit vote.
And it says you didn't select a choice. Perfect. That's exactly what we want it. Note, the code for
our vote view does have a small problem, it first gets the selected choice object from the database,
then computes the new value of votes, and then it saves it back to the database. If two users of
your website try to vote at exactly the same time, this might go wrong, the same value, let's say 42,
will be retrieved for votes. Then for both users, the new value of 43 is computed and saved. But
44 would be the next expected value. This is called a race condition. If you're interested,
you can read avoiding race conditions using F to learn how you can solve this issue. Okay, that's a
little bit advanced, it would have to be literally at the same like fraction of a second. could it
happen? Yes. If you're trying to scale your app to a lot of users? Yes. Should you worry about it
right now? Hell no. So let's continue. Alright, so remember what I mentioned in our views,
some of the code is looking similar like here, these are detailed views, right? They're showing
the specific question. And they need one specific question. Looks a little redundant, right? And
then we're using also specific question like allowing us to vote here, but these, there's a
little bit of redundancy going on. So how can we address this? How can we manage this in a better
way? Well, luckily for you, Django has something called generic views. These are class based views
that essentially have you once you use them. You don't even have to write down much real code. It
just does a lot of the things automatically in Pretty intelligent way. So I like this and check
it out. Alright, the detail and results views are very simple as mentioned above, but they're
redundant, okay? The index view, which displays a list of poles is similar. These views represent a
common case of basic web development, getting data from the database according to a parameter passed
in the URL, loading a template and returning the rendered template. So we pass stuff, and we get
it from the URL, and then we load up a template and we return the render template. That's
essentially what we have been doing. And when I say return the render template, another way to
say it is returning that HTML file you're looking for right or that page on the front end that you
see. Because this is so common, Django provides a shortcut called generic views system. Generic
views, abstract common patterns to the point where he doesn't even need to write Python code
to write an app, you could literally be sleeping, and the app just writes itself. Let's convert our
poll app to use the generic view system. So we can delete a bunch of our own code, we'll just have to
take a few steps to make the conversion. We will one, convert the URL cons, delete some of the old
unneeded views and introduce new views based on generics. Generic Django views. Alright, read on
for details. Okay, so why the code shuffle? What they're basically saying is, hey, you should know
basic math before you start using a calculator. So why did we do this up until this point, only to
now refactor our code? Will we have to refactor our code all the time? No, you will not. Next
time, when you're doing your app, you already know how the class based views work, you'll start
from more generic class based views. So basically, what they're saying is like, hey, look, we don't
want to just give you the calculator before you can do basic two plus two, or in my case, in one
of my videos, I think I had to do 2000 divided by 10. On a calculator. That was a pretty sad
moment. And that has a lot of upvotes makes me sad to this day. I wish my editor took it out. Oh,
well, you don't always get what you want in life, but Django generic views comes pretty close. So
let's keep going. Alright, amend URL con, First, open the polls slash URLs, r p, why you're
on Khan, then change it like so. So we're going to go and pull slash urls.pi. And I'm just
going to paste it over this bad boy and explain what the heck we just changed, right? So besides
the fact that we took out some notes, what else just changed? So let me let me take this out. So
you can kind of see it side by side and really see what changed. So if you look at this index thing,
all the change before it was just dot index, now it's index view.as. View, detail view as view
results. view.as view? And those are the middle arguments that changed, right? What are the other
arguments that changed? Everything after the name, all the name, keyword arguments remained the same.
But there was something else that changed. So here it says question underscore ID everywhere. But in
the new one, it says PK everywhere if you notice, right, so that's another big change to keep in the
back of your forehead. Alright. That's what they mentioned over here. Cool. So that's essentially
what we're going to be focusing on here. So here, we still have question ID, okay. Now, when we're
using these generic views, they take things in as PK, and they'll explain that later. And now we
need to make changes to our views. We're going to remove our old index detail and results views
and use Django as generic views instead, to do so open and change it like so. So we definitely
need this generic thing. So we're gonna do, we're gonna go to our views. And here we're going to
do from Django dot views import generic. Alright, so we got that. Other things that we need. Now we
need to make a class here. So I'm gonna completely remove this guy and add a little class here. How
will this work, it will automatically know which template to use based on this variable. These
variables are not just random, you can just call it this, it will not work. These variables have
to have this specific name for them to work. Okay, this is something important for you to remember.
Django does have a bit of magic but once you learn how it works, It'll be really, really
helpful. Okay. So template underscore name, you have to use this variable, we assign it
to the index HTML. For a context object name, we say latest question list. And for a query
set, we're just returning the last five published published options. Okay? So this we're saying,
only be referenced if somebody says this. So when somebody says this, you can get me that,
okay. Let's go in our class detail view. So for our detail, all we need to write is instead of
doing this get object 404, passing the question, passing the primary key and all that stuff,
and saying render requests, followed by the context dictionary and all that. It's pretty
simple. How is it working? Well, it's actually pretty cool. Um, okay, so let's go back to our
URLs. And since we're passing PK right in here, it already has it, you don't even have to pass it
as an argument or anything. Which model? Again, these variable names matter. We're telling it use
the question model, so it's directly communicating with this model right over here. template name,
we just give it the template name. And that's it. It knows what to do. Okay. pretty beautiful. Now,
let's do the same thing for results view. So it's going to change from this obfuscated looking code
to something pretty simple, check it out. Clean, right? Looks a lot cleaner, no need for request
and question ID no need for a get object or 404. No need for passing in question or primary
key, no need for saying render request. And passing in a context dictionary, it just
does it all automatically. And then vote, we're gonna keep it the same. Okay, we're gonna
hit Save. Now we're using two generic views here list view and detail view, respectively. Those
two views abstract the concept of display a list of objects. That's one concept. So list view is
going to do that. And then the other concept is display a detail page for a particular type of
object? So are you looking at the home page of Instagram? Or are you clicking into one particular
post, I'm looking at its detail. A generic view needs to know what model it will be acting upon.
This is providing using the model attribute, which is this. The detail view generic view
expects a primary key value captured from the URL to be called pk. That's why here it has to be
called pk. So we have changed question underscore ID to PK for the generic views, but not for the
non generic view. By default, the detail generic view uses a template called app name slash model
name underscore detail dot html. In our case, it would use the template the following template,
right. So if I go in my views, Paul, so app name, our app name is polls, slash results dot html,
so slash slash the model name dot html, okay. In our case, we just called it results at HTML. The
template name attribute is used to tell Django to use a specific template name instead of the auto
generated default template name. We also specify the template name for the results list view. This
makes sure that the results view in the detail view have a different appearance when rendered
even though they're both a detail view behind the scenes. So they're both a generic detail
view. Okay. Similarly, the list view generic view uses a default template called similar to the
other one, we use template name to tell ListView to use our existing one. So by using template
name, right over here, we're telling it which one to use specifically. In previous parts of the
tutorial, the templates have been provided with a context that contains the question and latest
question list context variables. For detail view, the question variable is provided automatically.
So the question variable is provided automatically instead of us even having to pass it in as
a context dictionary because generic views are smart. Since we're using a Django model,
our models called question Django is able to determine and improve Britain name for the context
variable. That's why it would pull out question. This would be the variable name that you can use
automatically on your front end in your templates. However, for ListView, to automatically generated
context variables, question underscore list. So if it's a list of things, right, like the list
of choices, or those answers, it would call them question underscore list. to override this, we
provide the context underscore object underscore name attribute, so we override it. And we give it
our own name. If we didn't give it our own name, we'd have to access it using question or score
list. But by giving it our own name, now we can access it on our template side as latest question
list. Okay, specifying that we want to use latest question list instead, as an alternative approach,
you could change your templates to match the new default context variables, but it's a lot easier
to just tell Django to use the variable that you want, run the server and your new polling app
based on generic views. So let's actually give it a try. My server is indeed running, I'm
going to refresh, I'll take a vote. And it voted correctly. I'll vote for the sky. And it
looks like it votes correctly. I will go to the polls like homepage, just polls. And it shows
me all the detail views for all of them. Right, what's new? And when I go on, what's up,
not only does it show me the detail view, but it also shows me the choices that go along
with it. So working fan in a fantastic way. Right, your first Django app, Part Five? So what
are we doing in this tutorial, we are going to be doing a lot of automated testing. Okay,
so what the hell is automated testing? Well, here, let me break it down in a simple, easy to
understand way. For you mere mortals out there. Let's say you have something like Amazon, right?
Something giant with millions of lines of code? Are you really going to like every time you add
a new feature, are you going to test all of the older features to make sure that they're working
correctly? Probably not, it's going to take up a lot of your time plus, you're going to kill
yourself. So what you're going to do is actually write these automated tests. So every time you
add a new feature to Amazon, let's say that you add this new cool feature that recommends new
shoes, you want to make sure that the ability, when user clicks add to cart, that still
works when a user clicks Checkout, that still works. So what you would normally do is go and
manually test it except because Amazon is so big, you're not going to be doing that. So you're
gonna write automated test, I'll test all of those things every time you add a new feature. So
when you add a new feature, it automatically tests everything that was before it. That's the point of
testing. Okay, that's kind of the beautiful thing about it. Okay, so why you need to create tests,
tests will save you time. Yep, they will save you a lot of time. Because let's say you were to
run into a bug or something unexpected behavior, you will know exactly why it's happening.
Or you'll catch on to it a lot faster. If you have code that tests those things. as you go
along. rather than waiting till everything breaks, the whole world comes falling down. And then
you're like, wait, what went wrong? Yeah, good luck finding the bug in your millions of lines
of code, right? You want to quality test, each thing as it comes in. Tests don't just identify
problems, they prevent them. Okay, so this helps you identify any problematic new bugs that could
be coming in. And not only like, identify them, but prevent them before it even happens. almost
think of testing kinda like if you just hired people without interviewing them. I mean, you
would have no, right, you would hire people like this guy. And you would have people who you
would have no control over, don't know. And like, let's say something was going wrong in your
company, you're not going to know who to blame, because you never really tested any person, right.
But if you run through an interview or a test with them, then oftentimes you don't even have to hire
them. And you can kind of prevent it. Before that problems spreads. Or if they're awesome, then you
can add them in right to your company. Tests also make your code more attractive. So basically,
like, your code will look nice if you have tests otherwise, developers won't take you seriously and
test how teams work together. So if your team is working, and some complex applications will be
maintained by teams right and test guaranteed that call leagues don't inadvertently break your
code, and that you don't break theirs without knowing. So this way, it also helps you when you
get employed and you have a job. You know, a lot We'll help you identify like where the problem is
coming from and the people who are working with you on your team, they know exactly what you're
thinking. And won't cause problems in your code either. So those are the benefits of testing.
Now you have some basic testing strategies, something called a test driven development,
it's a pretty common thing. It's called TD d, t, d. d, okay? And basically, it's like testing
as you go, rather than wait till I write my millions of lines of code and then freaking
test it right? Wait till I have 30 employees, and then I'll ask them and interview them and find
out like, don't do that test as you go. Okay. Now, all we're gonna do is we're gonna write our
first test. So, oh, we identify our bug who look at that. Well, they purposely planted a bug
in our code. And now we're going to use testing to solve it. Okay, we're gonna go Sherlock Holmes.
Alright, so fortunately, there's a little bug in the polls application for us to fix right away.
The question was published recently. So you guys remember that a little method we had was published
recently in our models for question. Well, it had a little bug. And basically how it works is the
method returns true if the question was published within the last day, which is correct. So if it
was within the last 24 hours, it shows you true, but it also shows you true if it was published in
the future. Okay. So it shouldn't say that it's recent, if it was going to happen in the future,
right? You wouldn't say, Oh, I recently got a car, if you're going to get a car 20 years from
now, when you finally get a job, right? So I'm just kidding, you probably already have a job
I don't. Let's continue to check if the bug really exists using the admin create a question whose
date lies in the future and check the method, check and check the method using the shell. So
first, we're going to check what's going on using the shell. Alright, so let's go back to our code.
Alright, so the first thing we're going to do is run our Python. So we're gonna run that from
we're gonna do Python managed up py shell, don't just do Python and hit enter, like an idiot
like I kind of did. So once you run the Python with this particular shell, then what happens
is you can like import your, you know, models and everything. Okay, so now import date time,
we're going to do from Django dot utils, import timezone. And then we're going to do from polls
dot models import question on. With that said, Now we're going to create a question instance with
the publication date, 30 days in the future. Okay, so how does this work? We're going to create a
variable called a future question. And we're gonna create it from the question class. And we will
say the pub date is equal to timezone dot now, so we're saying that it's published right
now. And then, but to that timezone, now, we're going to add some time to it. Okay, so
we're going to do date, time, dot time, delta, and we will do days is equal to 30. Just like
that. Okay, and then we're going to hit enter. So I say i'm saying is like, right now plus 30 days,
which in other words, translates 30 days from now. Right. So basically, right now, where I am at and
what my current day for me is February 20. Okay. 2018. So it's gonna do February 20 plus 30, days
after February 20. Okay, so no, it's not gonna be February 15. It's gonna be March something,
right? Cool. Was it published recently? Now we're going to ask it, and it should say no, it's not
published recently, right? It should return false, except that it returns true. So there you have it,
we know that something with our code is broken, right? So since things in the future or not
recent, this is clearly wrong. Now we're going to create a test to expose the bug. So right
now we expose the bug through the command line, right? We just use the interactive terminal shell.
But like, you don't want to be doing that every single time. You also don't want to be doing that
manually, every single time. So we're gonna write a test for it, they'll automatically test it for
us. Okay, cool. So now we're going to go into our test file and write this code and then I'll kind
of break it down. So in our under our polls app, we're going to go into our tests and we will paste
this guy here. Okay, I copied over everything and I pasted it over it. So what's going on?
we're importing date time, just like we did in the shell. we're importing timezone nor importing
test case. And we're importing the question model from our models. And how is this working? The
class is we're calling a question model tests. So the good idea is like, every time you want to
test, a model, make a class for that test. Ok. So this way, it's nice and organized. This class
inherits from test case that's coming from here, you kind of put that in without really thinking
about it. Okay, just like, look at the Django Doc's is saying, and just like follow it all
along, it's not necessary for you to like, learn about this test case class and how it's being
inherited and like, get a PhD in it, you can, but it's not necessary. And then, for a year,
the name of the function that you're testing, you want to a good practice, you want to like
break each thing you're testing have a function for that particularly, right. So for example, if
I go into my models, I have a method called was published recently. So since we want to test that
specific method, under that class, look, I'm doing test was published recently, right? And name,
the test make it pretty specific. So somebody who's reading your test method, or your test
function should kind of know what it's supposed to do just from reading the name. So we're testing
was published recently, but with future question, so what if the question was like, published 30
days in advance? Right? Here's the documentation for it was published recently returns false for
questions whose publication date is in the future? Cool. That's what it's supposed to do. Except
it doesn't do that. So now we're checking this, okay. We're saying, hey, set the time to 30 days
from now, that's what this is doing. And then we make the future question just from question
class. And then we set the publication date to that particular time from here, line 16. And
then on line 18. We're just saying, hey, assert, if this is this, however, this turns to true,
as we saw earlier, right, like right here. So this is gonna this whole thing, what if you run
it right now is going to turn to true. And that's really the problem that we're having, right? And
we need to fix that in our tests. We'll expose it, how do we run our tests, we're just going to go
to our command line. And we're going to do Python managed up pi test polls. So I'm going to exit
out of this exit. And now I will simply do python manage.pi. Test polls. So what I'm saying is like
test the polls app, and then it'll automatically basically run the test.py file inside of the
polls, after you created, run it. And look, it says failed failures is equal to one. And
basically, it says assertion error, it tried this line solve that assert is and what it found out
was this was not this. And so it's an assertion error, and it says true is not false. Now,
if this whole thing evaluated to false, which is it's supposed to, then it would go false
as false. And then this thing would return true, and it will throw any errors, okay. Now, as you
have more and more tests in here, all you'll have to do is just run that once, or you can set up
a web server, it runs that once automatically. And that way, it'll only alert you if something's
broken. Otherwise, it'll just go silently. That's the beauty of tests. By the way, have you
guys ever heard the song Fly Me To The Moon, but I've been in love with it, and I can't stop
thinking about it's like playing in my head, non stop. Anyways, let's continue. So what happened
is this, Python managed up pi test pulls, looked for tests in the polls application. And explain
that to already. It found a subclass of the Django test, a test case, subclass. It created a special
database for the purpose of testing. If I go here, look, it says destroying test database. So it
created its own database from what was happening right now. It looks for test methods, ones whose
ones whose names begin with test. Okay, so it's looking for everything that starts with test.
If you don't have these, starting with tests, it will find it okay. So like, let's just say it
was like this, and I'll hit save, and then we'll also run this test polls. And it didn't even find
it. It said ran zero test and zero seconds. But as soon as I do that, and if I run it, boom, ran.
It created a in tests was published recently with feature requests, it created a question instance,
whose publication field is 30 days in the future, right over here. And using the cert is method
discovered. It was published recently returns true though we want to return false what we found
out here, cool. The test informs us which test failed and even the line on which the failure
occurred. So here, it'll tell us which line we failed on line 18. Right? This is line 18. Cool.
So now we're gonna go ahead and fix this bug. How are we going to fix it? Well, this is the code
that's gonna help us fix it, we already know what the problem is. amend the method and models up UI.
So it will return true if the date is also in the past. So we're gonna go into models. And we will
change this to this indentation and whitespace in Python is important. So make sure it's indented
correctly underneath this was published recently method. And basically, we're saying, hey, set the
timezone to now like exactly right now and then subtract one day from now, if that's less than
or equal to the publish, and check if that's less than or equal to the self published date.
Okay, so if that's less than or equal to the published date, and then check if self published
date is less than or equal to now. Okay, so in other words, check that this publication date is
in between this. And this. Does that make sense? It has to be sandwiched between the two. And run
the test again. So now I'm going to hit save. And I will simply run the test again. And now look,
it says ran one test. And it gave me an okay, and it's saying destroying the database. So cool.
It looks like it had no errors. It ran all the tests successfully. If it showed me something red
or said failures, I know something failed. So now it's working. Cool. Now we can also do After
identifying a bug, we wrote a test that exposes it and corrected the bug in the code. So our test
passes. Many other things might go wrong with our application in the future, but we can be sure that
we want inadvertently reintroduced this bug. So it will automatically keep checking it and we will
we're not going to be reintroducing this bug, because we'll always find it because simply
running the tests will warn us immediately, we can consider this little portion
of the application pin down safely, forever. Pretty cool. I think that's pretty
freakin cool. And now they're like, Alright, we're gonna get into some more comprehensive tests.
While we're here, we can further pin down the was published recently method. In fact, it would
be positively embarrassing if in fixing one bug, we had introduced another. Cool, add two more test
methods to the same class to test the behavior of the method more comprehensively. So now we're
going to test was we're going to test the was published recently method with old question.
And then we're also going to test it with recent question. And we already have the future question.
So you can only have three cases, future question, recent question or old question. If a question
is older than one day, it should basically say that it's not. If the question is older than one
day, it will should return false, it should say it's not recent. If it's in the future, it should
say it's not recent. If it's been posted less than one day, then it should say it's recent. So for
example, if we just look at this test code at a high level, old question, look, it's ask it's
making sure that it's asserting to be false. So if it's one day and one second ago, right, so if
it's one, if it's exactly one day ago, then what it should do is it should say yes, it's still
true. But if it's one day and one second ago, now, I should say it's too late and it should be
considered false. Okay, it should be considered not recent, and then publish recently with recent
or with recent question. So the question is, as you can see here, not even one day ago, 23 hours,
59 minutes and 59 seconds ago, almost one day, it should assert it to be true. Okay. But take these
and we will go into our Our tests, and we will add this into our tests. Okay? There we go 12341234
and 1234123412341234. Okay, so just make sure that it's all indented correctly, and then that you
should be good there. So now we have all of those scenarios covered future old or recent question.
Let's run our test. And let's see if we have any bugs. No bugs, it looks like our method is working
perfectly. Okay. Just so you understand this code right here, it will only return true when the
publication date is in between this and that. Okay, so this is basically saying it's within one
day. And this is saying it's less than now. Okay, so if this is in between Illa match. And now
we have three tests that confirmed the question was published recently returned sensible values
for past recent future questions? Good. Again, polls is a simple application, but however complex
it grows in the future, and whatever other code interacts with, we now have some guarantee that
the method we have written tests for will behave in expected ways. Test the view so you can also
test views. The polls application is fairly undiscriminating, it will publish any question
including ones whose publication date feel lies in the future, we should improve this setting a
publication date in the future should mean that the question is published at that moment, but
invisible until then. Alright, so what are we doing here? Well, when we post our question, if
it's some data in the future, it shouldn't show it just like for example, on WordPress, if you
publish a blog post for let's say, you know, two days later, it doesn't show until two days later,
right, you can schedule your post or on YouTube, sometimes I schedule my videos. And you know, I'll
say real show this video to the audience in one week from now, right. So if I do show it from one
week from now, it shouldn't be showing it. At that same time, that would be crazy. That wouldn't make
sense. Just like that. We also want to do with our questions and make sure that it doesn't just show
out of nowhere. And we want to make a test for a view. When we fix a bug above, we wrote the test
first and then the code to fix it. In fact, that was a simple example of test driven development.
But it doesn't really matter in which order we do the work. In our first test, we focus closely on
the internal behavior of the code for this test, we want to check its behavior as it would be
experienced by a user through a web browser. Okay. So the first one, it was like the logic
of the code. This one we're focusing on what happens if the user is like, testing it, and
the user is actually on the front end of the website? What does it show to them. And isn't
that cool, so you can automatically test that every time your code runs, and you don't have
to like go and check if your cart is working, or your blog is showing things like that. Alright,
so the Django test client, so here's the command, we're going to go in our command line and type in
so I'm going to copy this guy again. And remember, we got to do Python, manage that py shell, then
paste this guy, and then we will get set up test environment just like that. Okay. installed the
template render, which will allow us to blah, blah, blah, blah, blah, okay. We will get this
guy and then we will also this say something about timezone, so make sure your timezone is correct.
Mine is in America slash Los Angeles, if I go in my settings and show you for you, it might be
something different. So you can go in this, go to this link and look up what your timezone is okay.
So we're going to import the client and then we're going to create an instance of the client. So here
we're creating an instance. And now we can get a response from our home page now. When the response
from your home page should give you something like not found or a 404 it's because if you go to your
home page, there's nothing there right if you just go to right now your localhost 127 dot o dot o dot
one colon eight And it should give you an error. The only routes that are mapped is like if you
go to slash admin or if you go to slash polls, remember that. So that's why the home is giving
us a 404. Right now, we should expect a 404. From that address. Let's just do response dot status
code. And here it is 404. We should expect to find something at polls though. Okay, so let's try that
we'll use reverse, rather than a hard coded URL. So instead of doing like, you know, whatever slash
polls, we're gonna just do a reverse here. Okay, so from Django, we're gonna import, reverse.
And we'll paste this guy right here. And now, if we do response, that status code, it shows
me something, if I do response, it's saying, template response status code is 200. And it's a
text slash HTML file, which it is. Okay, and now we can also get the content, we can do response
content. So now showing me the content of that file. And if you remember, we do have a unordered
list in the start. And then we have bullet points. So here you have what's cracking. in HTML to show
an apostrophe, they have to do this ampersand number sign, 39, semi colon, that's basically
apostrophe. And we also have another question what's new, and you can see their links here as
well. Okay. So this is like just showing the code version of what the user or we actually see on the
front end. And we can also do a response context and get the latest question list. And look
at give us the questions, what's cracking, what's new, what's up? Now we can improve our
view as well, the list of Polish, the the list of poll shows polls that aren't published yet.
Those that have publication date in the future, let's fix that. So right, that's a problem. So we
need to fix that. We introduced a class based view based on list view. So we're gonna go ahead and
fix things in there. Now we need to amend it. So let's go to our views and our index view, we need
to fix this. And changes that also checks the date by comparing it with the timezone. Now, first, we
need to add an import. So at the top of our code, we're going to add this here, import timezone.
And then our query set. We're going to change it a bit. So where is our query set? All right, can
we put this on one line? So it looks slightly less confusing? Yeah, we're fine. We're not following
Pep eight. We're running across a little bit. But according to my boy, Raymond, the Oji, heading
anger, or head injure. You know, according to him, he says 90 to 95 characters should be good enough.
Pepe, I think with the whole 80 character line, that's kind of stupid. Because, honestly, breaking
this down into new lines, messes up the code readability. But right now, this looks pretty
easy to read, if you just have it much easier if you just have it on one line anyway. Okay, what
is it doing? It returns the last five published questions, not including those set to be published
in the future. All right. So how is it doing that? It's taking the questions model. It's finding all
the objects and it's filtering those objects and only finding the following. Okay. This statement
here, it's looking at the publication date, and it's only finding so this underscore
underscore, lt means you're doing a reverse search. And you're saying less than or equal to,
that's what LTE means less than or equal to. So any publication date that was less than or equal
to the current time meaning only past or current posts, filter those. And then once we find those,
we order those by descending publication date. So which one was the most recent ones? And then we
show the first five, that's it. Okay. A lot going on. And now we can also test our new view. So
now you can satisfy yourself that this behaves as expected by firing up the run server, loading the
site in your browser creating questions with dates in the past and future and type checking that
only those that have been published are listed. You don't want to have to do that every single
time you make a change that might affect this. So let's create a test based on our shell session
above seashells. See, what is it? See She sells seashells down the seashore. Okay, as a falling
two poles slash test dot p y poles. Alright, we're adding reverse boom. And we'll create a
shortcut function to create questions as well as a new test class. So this will create questions for
us. Cool. Since this is not going to be a method is going to be a function, we're going to put it
outside like that. This will create questions, how will it create questions, you give it a
question text and you give it days? And then what it does is it'll create a question Would that
number of days in the future? Or would that number of days in the past based on whether you pass in a
positive number here, or a negative number here or something like zero? Okay. Right here, and then it
goes into question that I've just entered creates that object in questions class. And for the
question, text keyword argument and passes in question texts, and for the pub date, keyword
argument passes in the time, which it gets from here. Cool. Cool. Okay, so question view index,
what are we doing there? Question view, question index view test. So we're creating a new class
here. So I'm going to go right there and paste it and save. So now we're creating tests for our
index view. Instead of model. Okay, so this is our model test. And what we're saying is like test no
questions, if no question exists, and appropriate, and appropriate messages displayed. So if I go
into my views, and you can see, in my views, let's see, is there is it not there? Or is it an R
h, I think it's in our HTML right index. So here, you can see it says if there are recent questions
and show them else said, No polls are available. So we want to test that it actually does
say no polls are available on our front end, we can actually do that, and right here and we
say, hey, first, check that the status code for this page is a 200. Meaning that you actually
find this page second test that that response that you find it contains no polls are available.
Okay, so right now, remember, we have no questions at the moment. And then also, make sure that
the cert query set is equal to the response is equal to the following. So this thing? latest
question list should be empty. That makes sense, right? That means there are no questions, such as
a no polls are available. And it should check that this is actually just an empty list. Cool. Now,
what we want to do is test past questions. Okay, again, this could go on, could this go on one
line, or this will be too crazy? This is pretty crazy. So I can I can break that up a little
bit. That's fine. Still readable for me? Okay, so we're saying? If we create a question,
okay. Again, this creates its own database, so it doesn't have our what's cracking and
whatever tests available anymore for these tests, it creates its own database, and then it destroys
that database afterward. So within this database, we're creating a question and the question texts
will be called past question instead of what's cracking or what's poppin or whatever. And we're
gonna say that it should be 30. It should have been created 30 days ago. Okay, so this is a past
question, hence, test past question. And then what we're going to say is, hey, response, get that
particular page. And once we get that page, we want to say, Hey, is the are the latest questions
of that page contain that question? And the answer will be yes, it does. Because we just created it.
Right here. And if this thing is equal to this, then the test should pass. We're also going to
create a future question. So this should test a question 30 days in the future, pretty much
the same thing. And make sure that a response contains no polls are available. That makes sense,
right? Because if the question is in the future, then it shouldn't be available right now. So it
should say no polls are available. And also make sure that the response context latest question is
empty. Because there are no latest questions is going to be posted in the future. Okay. Cool.
And let's check this guy with the recent and past questions. Again, think it's a little bit
more readable like that. You can break it down like this, that should be fine, too. But I like it
like this. And basically, what we're testing here is that this thing should equal to this thing.
And what's going on here? Are the doc for this as this is test future question and past question,
even if both past and future questions exist, only past questions are displayed. That makes sense
to and how does it work? We create a question 30 days in the past, we create a question 30 days in
the future? Question. One is called past question. Question two is called future question. We get the
polls index page. And then we say that this thing, the latest question list should only have
the past question those created 30 days ago, and not the recent question. And it should match
that. And indeed, and it should, right? If we did everything, right, we shouldn't get an error if we
run this. And then all we need to do is define to past questions. All right, now this is getting
a little too big. So let's break this one down now. And you can indent this too. Okay, so what
am I saying here? I'm saying? So test to past questions. So the questions index page may display
multiple questions. So we also want to see that it doesn't just display one question. It displays
multiple ones, right? So we have past question, one, which was created 30 days ago, we have past
question two, which was created five days ago, we get the polls index page. And then we say make
sure that the question list. Actually, let's do it like this? Because I think it's more readable,
actually. So you want to say that this should equal to this? latest question list should have
both of the past questions. Why in this order? Because remember, the most recent ones it shows
at first, right? If we look at our views, and how it does it, ascending order, sorry, descending
order, and then the five. So that's why that's why I would show the past question to first.
And then this one right here. Cool. Basically, the most recent question and show all the way
at the top. Alright, so first of the question, shortcut function, create question to take some
repetition? Yeah, well, we pretty much went over this whole thing. So we don't have to check that
answer. So on in effect, we are using the test to tell a story of admin input and user experience
on the site and checking that at every state. And for every new change in the state of the system,
the expected results are published. Now. That's a really important point, like you're telling a
story with your test guys like this is what's really important to understand. So if you're
working on a team with somebody and somebody is reading through your test, they understand
what each of your view is supposed to do, and what it's supposed to return like so so,
so key, like if I'm looking at somebody's code, I don't know what the hell it's supposed to
do, right? I don't know what the right answer is supposed to be. But if I look at their tests,
and they have like bunch of examples, and what the correct answer and the wrong answer should be
and that these documentation I totally understand what each function is supposed to do what each
class is supposed to do. And then effectively, I'm on the same page. And then I can actually
contribute to this project, right, I can go, that's where you guys hear like, hey, just go
ahead and contribute to open source projects is one of the ways that you can do that. Understand,
look at their test first. And then, like, I can't tell you enough, for those of you who are a little
bit more advanced to understand the library, here's a pro tip, one of the best ways to do it is
not just like, instead of just reading the code, go and look at their tests, and they will have so
many things in there and what it's supposed to do, you'll start understanding how this library
supposed to work, and it's how it's supposed to behave, literally tells a story. Now we want
to test the detail view. Okay. So what we have works well, however, even though future questions
don't appear in the index, users can still reach them if they know or guests the right URL. So
we need to add a similar constraint to detail view. Okay, so we don't want to our users to
be able to reach those questions, obviously, because they don't exist. So they shouldn't just
be able to go to that particular URL. Okay, like, let's say you had a blog post, like, whatever
your blog post is called banana. So it's like, john comm slash blog slash banana. If
you scheduled it for like, a month later, I shouldn't be able to just go to it from the URL.
Okay, so what's going on here? We have the detail view. So let's go into our views. Let's go into
our detail view. It's right here. What do they want us to do? They want us to create a query set
and do this with it. Okay, excludes any questions that aren't published yet. So filter, make sure
the publication date is less than or equal to, then the time zone now. That's, that's it. That's
essentially it. And those are the only ones you can check. Pretty cool. Okay. Very, very powerful.
Again, you can see how powerful the generic method is. And of course, we will add some tests to check
that a question is publication date is in the past can be displayed, and now one with the publication
date in the future is not. So let's go into our tests. And let's add the test for this. So again,
it's a new class, it should have its own methods and everything, right. So for the index view, we
created a class. Okay, for those tests. And now, for our detail views, we're also creating a class.
Okay, very important. Now we test future question and we test pass question, how do we do that?
We create the question five days in advance, we send you to the polls Detail page. So like, for
example, on Instagram, if you click into a image, and it shows you that specific image that's
equivalent in our app of polls, detail, or questions, detail view. And for the arguments, we
give it that questions ID from right here. And as a response, we get that particular URL, and then
we say, hey, make sure that the response actually returns a 404. And it will, because here's
how we told it. And then test pass question. So basically, here we're saying 404, meaning
it doesn't exist, right. So the detail view of a question or the publication date in the past
displays two questions, text. So past question we create the question here is created five
days ago. We get the URL for the polls detail, and we pass an ID for the past question. And then
as a response, we get that specific URL. And then we assert and make sure that it can the response
contains the following thing. So response, and then it should have the question text in there.
Okay. It's a past question. Question text. Cool. And, let's see. Let us Let's see if we're gonna be
using any more command line stuff or not. Let's go an exit. And let's just see right now for tests
are working. In our poll slash views, something's happening on line 18. What is happening? Ah, oh,
okay, it's not indented correctly, obviously. Save up and Enter. And look at that all our tests ran
in here. And they all ran successfully. So you can see all these tests have already gotten pretty
complicated, and they're testing our app pretty thoroughly. You know, this is not something you
want to do manually every single time, and you can already see the power of it. Alright, ideas
for more tests. So we got to add similar query set method to results view and create a new test
class for that view. So we can also test results view. It'll be very similar to what we have just
created. In fact, there'll be a lot of repetition, we could also improve our application and other
ways adding tests along the way, for example, it's silly that questions can be published on the site
that have no choices. So our views could check for this and exclude such questions. Our tests
could create a question without choice and then test that it's not published, as well as create a
similar question with choices and test that it is published. Also, you can have logged in admin
users who should be allowed to see unpublished questions, but like ordinary visitors shouldn't
be. So if you're an admin, right, and you have WordPress blog, and you schedule one in advance,
you can see it but other people can't just like, I can't schedule my YouTube videos, you can see it
I can. whatever needs to be added to the software to accomplish this should be accompanied by a test
whether you write the test first and then make the code pass the test. This is the test driven way
of doing it. Or work out the logic in your code first, and then write a test to prove it. At a
certain point, you're bound to look at your test and wonder whether your code is suffering from
test bloat, which brings us to the following. So the thing that they say is when testing more
is actually better. Okay. So it might seem that your test is going out of control. And there's a
lot of like test bloat. And you know what? Your beautiful, elegant and concise code compared to
your tests looks so much better. That's totally okay. Tests are supposed to be bulky and a
lot. And they should cover your ass. Okay, that's their job. And so they don't have to look
pretty, they don't have to look beautiful, they have to tell a story and have to tell it clearly.
So it doesn't matter. Right? let them grow. And for the most part, you can write a test once and
then forget about it, it will continue performing its useful function. As you continue to develop
your program. Sometimes they will need to be updated just like we had to update ours, telling
us exactly which test needs to be amended to bring up to date so that extent, tests help look after
themselves. At worst, as you continue developing, you might find that you have some tests that are
redundant. In testing redundancy is actually a good thing. And even that redundancy is not a
problem. Okay? So the more you test, the better and you don't have to go back and wipe anything
clean. As long as they're sensibly arranged, they won't become unmanageable, okay? So the good
rules of thumbs. Good rules of thumb include the following. You should have a separate test class
for each model or view. So for remember, for each of our models, right, or question model, question
model test, we had a different class for this. And for each of our views, we actually had a different
class for a detail view, we had a different class for our index view. And if you wanted to go
further, we could also add a different class for our results view. A separate test method for each
set of conditions you want to test. So instead of testing test, no questions has passed question and
kind of like testing an all in one, it's a good idea to break it down into separate different
tests. Each test doing only one job so here if no questions exist, and appropriate message
displayed, that's what this is. Test is supposed to do. This test over here. Questions with the
publication date in the past are displayed on this page. Like you can see each each test is
trying to do one and one thing only. Okay. test method names that describe their functions. So the
names themselves should describe the function of the test. Okay, so test no questions, test pass
questions, test future questions. And once you build this naming convention, you and your team
starts understanding it. And most of the times, you guys will be able to just look at each other
tests and know what your app is supposed to be doing, or it's not supposed to be doing. further
testing, this tutorial only introduces some of the basics of testing, there's a great deal more that
you can do and a number of very useful tools at your disposal to achieve some very clever things.
For example, so this is a pretty cool part. Right now, we just kind of tested our back end and
a little bit of our front end. But what if we wanted to test our JavaScript and how it loads and
literally, like, moving the mouse, like have the computer, move the mouse and select one of the
votes and click vote? How does that experience work? How can we test that on autopilot? where
it happens automatically? Well, there's something called selenium, selenium, or Selenium. And
it's a way to test your HTML actually renders in a browser. Okay. So these tools allow you to
check not just the behavior of your Django code, but also, for example of your JavaScript and your
browser, pretty freaking mind blowing. It's quite something to see the tests, launch a browser and
start interacting with your site as if a human being were driving it. And Django includes live
server testcase, to facilitate integration with tools like selenium, okay, so if you want to get
more advanced, look up Django and selenium. And you can even look up YouTube videos online and
add those kinds of tests within your app. If you have a complex application, you may want to
run tests automatically with every commit for the purposes of continuous integration. So if you
guys know about GitHub, and commits, you can make it so that when you're writing the code, and as
soon as you commit it, I like to call it like the time machine, because that's what Git and version
control allows you to do. You can make it so then it tests it on every commit. So that if any one
of your commits, you know fails any of the tests, it'll be like, Hey, this is broken. And you'll
find out right away, before you actually push that code onto GitHub, and destroy your life,
embarrass yourself, Let down your family and be fired from your job. So that quality control
it is itself at least partially automated, a good way, a good way to spot untested parts of
your application is to check code coverage. This also helps identify fragile or even dead
code. If you can't test a piece of code, it usually means that code should be refactored or
removed. that's those are some big words. coverage will help to identify dead code c integration
coverage dot p y. And you can check you know what's dead code and what's not. And, yeah, so
a lot of testing, I hope that you enjoyed that. We're going to be covering essentially how static
files work in Jango. Okay, and how you can use them to customize your apps look and feel. Okay,
so without any further ado, let's jump right into it. Okay, so writing your first app, Part Six,
right? So how are what are we doing now? Now we've built a tested web poll application. If you
haven't done that, go back to part five. If you haven't done part five, go back to Part Part Four.
Make sure you're following this in order. And now will now add a stylesheet and an image. Okay. So
aside from HTML that your app generates, right, and shows which is your front end, so far, the
voting thing that we have, or it shows some text with radio buttons, your website needs to be able
to do other things to like show people images, or pictures of cats or blog post images. It also
needs to be able to serve up JavaScript if you have any JavaScript, right? So for example, if
you don't know what JavaScript is, is totally fine. But like, anytime you're clicking a button,
and it like pops up a menu kind of thing. That's usually JavaScript going on there. Okay. If
you click something like a pop up comes up, there's JavaScript, JavaScript is pretty much
everywhere. So your website needs to be able to show some JavaScript and it also needs
to be able to serve CSS, okay, which is, it's called CAS stands for cascading style sheet
and you use this to stylize your app and make it look cool and beautiful. Okay. And yeah, so
that's usually what's necessary to complete a web page. In Django. We refer to these files as
static files. Now for small projects, right? This isn't a big deal, because you can just keep the
static file somewhere where your web server can find it. However, in bigger projects, especially
those comprise of like multiple attributes, if you have multiple apps like polls and blog,
and e commerce, like whatever, dealing with the multiple sets of static files provided by
each application starts to get tricky. That's why Django contrib that static files is there for
you, if you're a beginner, don't worry about this part too much. But this is for more advanced
people mentioning this part, okay? Otherwise, I've kind of skipped over. It collects static
files from each of your applications and any other places you specify into a single location that can
be that can easily be served in production. Okay, so now let's get to customizing your app's look
and feel. So first, we're going to need to create a directory called static in your polls directory.
Okay, so let's go ahead and do that. And I will open up, Adam, and we will go in our polls.
Hopefully, you can see that on the left hand side, I don't know how to make tab bigger. So I'm
sorry about that. But yeah, we're gonna go inside of our polls, and inside of our polls,
I think this is where it wants us to make it. So I'm going to right click this polls, not the
templates one. So right click, right click here, create a new folder and call it static. Done.
Okay, cool. And for those of you wondering, like, how do I switch like that it's command and tab,
and on Windows, that's all done tab. Cool. Django will look for static files. They're similarly
to how Django finds templates inside polls, template polls slash templates. So you know how
there's like polls slash templates, and Django automatically looks for templates there. Well,
just like that, for your static files, Django is going to look inside of your folder static.
Okay, so Django static file setting contains a list of finders that know how to discover static
files from various sources. One of the defaults is AB directories finder, which looks for a static
subdirectory in each of the installed apps, okay, so Django will automatically look for a folder
called static under each of the installed apps. Okay, so right now, we have polls as one of our
apps that we created. And remember to install this app, we had to do this line in our settings
file under installed apps. And then, now Django is able to find its static folder. If you have
another app, again, like a blog app, and you have static folder under there and you install the blog
app, then you'll be able to then Django will be able to find the blogs, blog apps, static files,
okay, like images, JavaScript, CSS, those are all considered static files. All right, the admin uses
the same directory structure for its static files. Cool. So admin site works the same way. Within
the static directory, you've just created creating another directory called polls. So inside of
static, we're going to create another directory, and we're going to call it polls, okay? So kind of
like how you have polls, templates, polls, you're gonna have polls, static polls, okay, similar. And
then inside of here, we're going to create a file called styles dot CSS, I'm going to do new file,
and I'll do style dot CSS, just like that. Okay, so this is our CSS. Again, in the command line,
if you haven't activated your virtual environment, make sure to do conda or sorry, source, activate
my sites. If you haven't done that, just in case you need to do something in the command line,
which you're not going to in this video i don't think because of how the app directories find
your static files. Find your works you can refer to this data file and Django simply as polls slash
styles dot CSS similar to how you reference a path for templates. So remember how for templates
you just go pole slash index dot HTML well for this is pole slash style dot CSS, okay. And
for namespacing it's just like templates. So the same reason why you put templates under the same
reason why you make a new folder called polls, under templates is the same reason why you create
another folder called polls under static it so then if you have multiple different apps, there
is no collision based on like you having the same name for any of your CSS files or any of your HTML
Mel files. That's what they're saying here. Okay, now we're gonna do some fun CSS stuff, okay,
and we're going to keep it pretty simple. So in our style dot CSS, what I'm basically saying is
that any link tag under a bullet point are listed thing, color red and green. Okay? So A stands for
is like your link tags, anything that contains a link, basically returning for now returning almost
all of our links on our current site green. Next, add the following at the top of polls, slash
templates, slash polls slash index dot HTML. So we're going to go in our templates polls index
dot HTML, and at the top we're going to add is we're going to say load static. So we're going to
add that right here, load static. So what this is not able to do is load our static files. And
then right here, I'm going to add this. So I'm creating, I'm creating a link to a stylesheet. The
type is text slash CSS. And the link is this. Now I'm using the link in a dynamic way. This is
the best way to link it instead of like hard coding natural path. And you just say Polo slash
style dot CSS, okay, that's how we refer to it. And that's pretty much it. Okay, so now, let's
go to our, our website. So I'm gonna do Python, manage that py run server. And we're gonna
open up a new tab, and I'm going to go 127 that slash 1000. Or I'm sorry, slash polls.
And you can see that all the links are green, right, if I go back to my stylesheet, and turn it
into something else. So let's go back into sorry, style that CSS is right there, I'll bring it
here. If I change this to like blue, save, Command S go back here refresh, you can see that
all of this is now blue. If your didn't turn blue, close out of your server, or break the server with
Ctrl C, and then try it again and then should be fixed. And Yep, there we go. And also make sure to
save Okay, and another way to go to this same link is doing HTTP localhost colon 8000. Slash polls,
okay. And that should take you to localhost colon 8000 slash pauses the same thing as your
127 dot o dot o dot one colon 8000. Do the same thing. Alright, so that's essentially how
we got that to work. Bring this guy here. Now, we also can add a background image. Okay, so we'll
create a subdirectory for images create an images subdirectory. So basically, inside of our static,
and polls, we're going to create static holes, we're going to create a new directory, and we're
going to call it images. This is where we're going to put all up all of our images. So it
should look like this. And then you can put whatever image you want, right background dot GIF,
or. So what we'll do is we'll go online and like, grab an image. So let's get cats. Right click,
and then just save the image. And you can save it whatever you I'm going to call it like
cat back round. Oh, sorry, we can just save it wherever we want. I'm going to save it under
my site, my site, or sorry, polls, static polls, images, and I'm going to save this cat underscore
background. And it's automatically dot JPG file. Because I have the format selected like that. I'm
going to hit save. It saved I'm going to open up my atom. And under images, I now have my cat
background JPEG. So let's go back to this tutorial. And it's basically saying to do this,
add this to your style sheet. So I'm going to add this now, I'm going to say so from images
instead of background that GIF mine is called cat underscore background dot jpg, like that. So
now, it's gonna find basically in our HTML code, it's going to find anywhere we have the body tag,
it's gonna make its background, this cat image, okay, so if I go to, you know, our index dot
HTML, if any of this stuff is In a body tag, it'll add that to the background. So let's check
it out. It says, and you should see the background loaded in the top left of the screen. Okay, let's
give it a try. Let's see if they're in line. And there you go. It's there, right? So pretty cool
how it works. And what I could also do is I could go to my index dot HTML, and like wrap maybe
a certain part of it in the body tag. So like, maybe the part that's in the for loop, right? So
I can, I can go like, body tag. And I can choose to close the body tag outside of this unordered
list, I can go body like that. Okay, if I want to, and I go back, I refresh. And the same thing.
Okay. So this is essentially like a little bit of how HTML and CSS like talk with each other.
Okay, and now let's look at kind of their last notes here. So there, okay, so warning, of course,
the static template tag is not available for use in static files, like your style sheet, which
aren't generated by Django. So in your CSS file, you can't use something like, static. Like that.
It's not going to know what that is. And you can do like if then statements here. These are just
your static files, hence, they're not dynamic and can't do like variables and cool stuff, right?
Like your index, your HTML file can with the, which has a Django templating. system. And in
there, you should always use relative paths. So here, we're not using like, slash user slash
clever programmers slash GitHub, slash my site, slash my site or slash polls, slash what else is
it? static slash polls slash images, right, we're not using the absolute path. That's the definition
of absolute path, we're using a relative path to it. Do you're satisfied between each other because
then you can change static underscore URL. So this is again, a little bit more advanced. I'm gonna
I'm gonna skip over this one. But you can read that if you want. And that's essentially how you
work with general like static files on Django. There you have it, folks, I hope you enjoyed this
tutorial. I hope it was informative, and juicy, and you loved it. If you did love it, please leave
a comment, please like it and share it with at least one friend. Because if you have at least one
friend or family member, sorry, what's happening in my mind, if you have one friend or one family
member who's doing development alongside you, is going to boost your success rate up by at least
60%. They have like scientific studies on this. So share it, maybe somebody will watch it alongside
and you will become web developers together.