Django 101: Django for absolute beginners | Kalob Taulien | Skillshare

Django 101: Django for absolute beginners

Kalob Taulien, Web Development Teacher

Django 101: Django for absolute beginners

Kalob Taulien, Web Development Teacher

Play Speed
  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x
22 Lessons (2h 8m)
    • 1. Welcome to Django 101

    • 2. Using a virtual environment

    • 3. Setting up Django

    • 4. Creating a new app

    • 5. Your first Django model

    • 6. Your first view

    • 7. Setting up your templates folder

    • 8. Using template blocks

    • 9. Custom page context

    • 10. Displaying dynamic posts

    • 11. Adding images to your model

    • 12. Setting up your media folder

    • 13. Adding images to your template

    • 14. Adding a detail view

    • 15. Detail template

    • 16. Template links

    • 17. Adding an upload form

    • 18. Sorting default posts

    • 19. Django messages framework

    • 20. Adding Bootstrap 5

    • 21. Your project

    • 22. Summary

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.





About This Class

Welcome to Django 101: Django web framework for absolute beginners! 

Django is one of today's top web development frameworks, written in Python. It makes coding a website very quick and easy, and keeps it secure. Django is 100% open source, but don't let that fool you — Django has been used to create websites and apps like Instagram and Pinterest — some of the highest trafficked and most used websites today.

Why learn Django web framework?

.. Because Django is an in-demand web framework. And because Django is powered by Python, one of today's top programming languages, it can do anything a super powerful software program can do. 

And also because Python and Django developers earn more as professional programmers (remember: always learn what's in demand; don't learn something just because the internet says it's "cool")

Two ways to learn Django:

1. Function based or,
2. Class based.

Function based is very simple but doesn't leverage the power that comes with Django. Admittedly there's less "magic" happening with function based views, which is sometimes nice. 

Class based leverages all of Django's power. It lets you write less code and do more with it. It's incredibly powerful. In this course, we're using Class Based code because that's what the professionals are using. My job is to prepare you for real-world web development

Who is this class for?

Absolute Django beginners. But be warned — you NEED to know Python in order to write Django. This is very important. And there's an added emphasis on Python classes, because we'll be writing a lot of those.

What will you learn? (Don't worry if you don't know what any of these are!)

  • Class based views
  • Django model management
  • Template parsing 
  • Django forms
  • List and Detail views
  • Dynamic URLs for your website 
  • Creating a new Django app from scratch
  • How to use Pipenv for your virtual environment 
  • Uploading images
  • Creating image thumbnails 
  • Using a 3rd party package
  • And so much more

Who is your teacher?

Your teacher is Kalob Taulien — he's been writing Django websites for 4+ years now. Python's #1 content management system called Wagtail CMS — Kalob is also a part of that core team. He's trained and personally mentored developers to become good enough to secure a job as a professional web developer.

What is your project?

In this class you will be creating a brand new Django-based website where you can share images from your computer on your website. Basically, we're creating a basic form of Instagram.

Meet Your Teacher

Teacher Profile Image

Kalob Taulien

Web Development Teacher


Hi everybody! I'm Kalob Taulien.


Here's the TL;DR (short) version about me:

I have been coding since 1999 and teaching people how to code since 2013 I have over 350,000 web development students world-wide I'm on the Wagtail CMS core development team (Wagtail is Python's #1 most popular website making system) I try my best to answer EVERY question my students have  I love teaching — it's definitely one of my natural talents  Also I love goats! (Great conversation starter with me if we ever get to meet in person)

Below you can find all my Skillshare courses. The categories go from easiest to hardest, except for the Misc. Coding Courses at the very end. 

If you're brand new to coding, start with BEGINNERS WEB DEV.&nb... See full profile

Class Ratings

Expectations Met?
  • Exceeded!
  • Yes
  • Somewhat
  • Not really
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Your creative journey starts here.

  • Unlimited access to every class
  • Supportive online creative community
  • Learn offline with Skillshare’s app

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.


1. Welcome to Django 101: Hello and welcome to Django 101. In this course, we are going to get started with Django, three firms scratched so you don't need any experience whatsoever. You are however, going to want to know a little bit of Python and Python classes in order to make the most out of this course and to make the most out of Django in this course, you can actually see the project behind me. We're going to create an image uploading project. It is a lot like Instagram. It just looks a little bit different and fun fact, Instagram was built using Django. And in this course I'm gonna teach you exactly how you can upload images just like Instagram and share them in a what's called a detail view. Just like Instagram. Hi, I'm Caleb toluene. And I've been reading Django for a number of years now. I raked Django for all of my projects. I think it is the best framework out there. I'm very passionate about Django, and I'm really excited to teach you how to write Django. Django is built on top of Python, which is one of the most popular programming languages in the world. It is incredibly powerful. And today we are going to be building this project. Welcome to my class and I look forward to seeing you inside. 2. Using a virtual environment: Alright, welcome to Django 101. Before anything we need to create a virtual environment. We always do this when we're working with Django or really any project whatsoever. So in order to write Django, you must know a little bit of Python. If you don't know Python, you probably don't have a text editor. So in front of me, what you see here is VS code. This is my text editor. On the left is going to be my folder, and at the bottom is going to be my terminal. So if I go over to View and then terminal, and the bottom is going to be my terminal. And so we are going to create a virtual environment and others. A plethora of different ways we can create a virtual environment. We can use Vagrant, we can use docker, virtualenv wrapper, a Python Vn via event, or we can use Pip env. And in this module I'm going to show you how we can do it with pip envy. So first things first, you probably already have Python installed. You should be able to do Python dash v. I'll be using Python 3.8. If that works for you, you can then type pip install PIP. And now I already have Pip env installed. So this is going to be really, really quick. This might be a little bit slower for you, but eventually that should be installed. And then we can type pip install Django. And this is going to create a new PIP enviroment for us. And we just give that a quick second to install Django for us. And this is going to install Django 3.1. We'll look at the exact version in just a second when this is done. Alright, now that that's done, we can do pip N shell to get inside of our Pippin environment and do pip show Django. And I'm using Django version 3.1.1 for now to get out of our shell, all we have to do is type Control D or exit and that's going to exit out for us. And to get back in, we just simply type Pip nth shell. And if we take a look at our files here, ls dash LA, or if you're on Windows DIR, it's going to give us a Pip file and a Pip file dot loc. Now at this point in time, if you have Git installed, you can do git init, git, add, git commit. Number one, setting up a Pip env. And then if we do this real fancy command, which is a fancy git log, you can see that our first commit here setting up a PIP and if you're not using good, that's okay. You can simply ignore that part of this video. I'm going to be using get moving forward. But again, if you're not using good, if you're using a different version control system, That's totally cool to, you can just ignore that part. In the next video. Let's go ahead and actually get Django setup. 3. Setting up Django: Okay, let's go ahead and get Django setup. So first thing is we need to do is we need to get inside of our virtual environments. Now I'm using Pip env. You can use Venn, Docker, vagrant, whatever abstraction layer you want. It's just good to have some sort of virtual environment in here. If we do Pip show Django, we should be able to see we have Django in there. If you don't have Django in there, you can always do pip install. Django is equal to, equal to 3.1.4 or whatever the newest version of Django is. And that will install Django for you. Next we can type Django dash admin, start project, and I'm going to call it my site. And then I type dot. And that's just going to put it right into this exact folder. So let's take a look at where we're at first. I'm on my desktop in a folder called Django 101. We can see that on the left here, Django 101. And so I just simply wanna type Django Admin, start project my site. And if you don't give it, the dot is going to create a sub folder in here called my site, which may or may not be what you want. I don't want that. I just want Django to create a brand new project in this directory that I'm in. Now if I do ls dash l a, or if you're on Windows, Windows you can type D-I-R dir. And we're going to see that we now have managed dot py and my site. And if we open this up on the left, we have all sorts of stuff in here. We've managed file whisking URLs settings as e and in init dot pi. Now what we can do here is we can, if I just clear this off, type D JAR, Django run server. So we type python manage dot py run server on 0.0.0 port 8 thousand. And this should say that yet we have an applied migrations. Now what a migration is is simply it's connecting to a database of some kind. So I know that it's connecting to an SQLite three database here. It's just a simple file and it's trying to provision my database so that we can set up users and permissions and all sorts of things. And whenever you see this red little and it's not really an error, it's more of a message that says, hey, you have 18 on applied migrations. You can simply type Python managed up pi migrate. And what this is going to do is tell Python whatever version of python you're using to execute managed at pi and its parameter or argument on the command line is just the work migrate. And so we run that and we're gonna see that all of these are now running. And then to run a server again, I just have the shortcut to comma comma d j, r because I, I run this command hundreds of times a day. So Python managed up high run server 0.0.0 dot 0 colon 8 thousand. And we should see this. Now at this point in time. If you see this, we can now open up our browser and we can head on over to localhost port 8 thousand. So we just type in localhost colon eight thousand. Eight thousand matches what we typed in our command line. And we should see this. Once you see this, you now have a Django project up and running successfully. Now this is cool, but there's nothing in here. So let's go ahead and check out the admittance. We can is there an admin link down here, Documentation, tutorial, Django community. There's no admin in here. So we can go straight to slash Admin and we need a username and password. So let's go ahead and set up a username and password, tunneled back over to our terminal here. And we can type Python managed dot py, create super user. And all I did there, by the way, when I was running the server was I just hit Control C to cancel. So I'm gonna create a new superuser. I'm gonna call it Caleb. No reply. Add Caleb dot IO. I'm gonna give it a password, retyped my password. And cool. Superuser successfully created that's our admin account. And then we simply run Python managed run server is 0000 colon 8 thousand again. Head back over to our browser, refresh. Just make sure this page actually loads the way we're expecting it to load. Type in our username and password. And voila, we are inside of our Django Admin. This is where we're going to be editing all of our content. We can manage pretty much everything through here, as long as we tell Django that it's supposed to be manageable by an administrator. So your task for this lesson is to install Django inside of your virtual environment and create a superuser. And don't forget to run your migrations. And once you see this page and also this page, you are ready to move on to the next lesson. 4. Creating a new app: Okay, let's go ahead and create our first app. And so Django does this funny thing where actually I don't know why they call them apps. It's kind of confusing because we're not creating a phone app or mobile app, but it's like a little mini application inside of our Django application, and so we call them apps. And so what we can do here is create a brand new app using a command that Django gives us. So we do Python manage dot pi, and I'm just inside of my virtual environment here. Python managed dot py, start app, and I'm going to call this feed. And if you look on the left, just give it a quick second. It creates a folder called feed. It has migrations and knit admin apps models up high and views dot pi. Now what we want to do is activate this. And in order to activate this, what we have to do is go over to my site, go into our settings.js and makes us just a wee bit smaller here. And what we're looking for is installed apps. And here we see we installed apps. Django, contrary to admin, auth content types, sessions, messages, and static files, these are all things that just come with, with Django. We don't need to worry about what they are right now as this is just a Django 101 course. So this is a list, a Python list, and I'm simply going to type the name of this folder in here. It's called feed. And let's go ahead and run our server once more. And we see nothing happens. If we see that nothing happens, this is good news. This probably means that you have installed your feed properly. That's all there is for this video, hopefully you're following along, don't forget, and you need to run Python managed up high start app, not start project, but start app. And then the name of your app and that's going to create a new folder for you. And then you go into your settings, installed apps, and install that app. Just put it at the bottom of your list of installed apps. 5. Your first Django model: Alright, let's go ahead and create a new model. And so what a model is supposed to do is not only does it automatically generate a table in our database for us. So Django is very nice in the sense that we don't have to manage our database pretty much whatsoever. It automatically does that through the form of migrations and models. And so a model is simply a way to write code in a form of a Python class. And it's going to automatically mapped to a database that we can't even see. And then we can go and modify some of that data. So in this lesson, what I want to do is create a new model in our feed just called posts. Then we're going to activate it in our Django admin so that we can see it. So I'm going to stop running Django. Not that that it was not that it was detrimental while it was running. There's no problem keeping it running. In fact, I'll show you that it can stay running while we're doing this. So we're going to open up feed models dot py, and it says create your models here. Let's go ahead and delete that comment. And let's type class Post models, dot model. And what this automatically does is if we were to tell Django, Hey, look for new changes called Migrations, it's then going to generate a migration file and then provision our database to make it have a table called feed underscore post. And that just allows us to create a simple way to store data. Now in this post, we're going to start very simple. We're gonna start with some basic text. And so in here we say text as a property is equal two models, dot char field, and this is just a character field. It takes a max length. And I believe the maxlength is usually somewhere around 256 characters. But let's make this like an original tweet, like a 140 characters. Then you're often going to see a another keyword in here called blank in that can be either true or false. By default, blank is false. And what that means is when we're filling out a form, does this field need to be filled out? Absolutely. Yes, it needs to be filled out. We're gonna say this is mandatory. And then we have another option here called null. And null can be true or null can be false. And when null is true, that means our database can store either no value and empty string or some sort of string. We don't want this to be null is equal to true, to be true. Because we always want this to be filled out in our database. So there's always going to be text. It can't be blank, it can't be empty text. It always has to be there. So lets say null is equal to false. Now let's go ahead and save this. And you see Django automatically restarted for me here. What I can do now is make a migration. So I do Python manage dot py, make migrations. And this is going to create a brand new file. And you can see in here, it created 0001 initial dot py. And all this does is create a python file that's now executable. And when we run Python managed dot py migrate, it doesn't have any dependencies. It's the first one and it has some operations in here. It's going to create a model or create a table in our database called post. And these are the fields it has an ID automatically, so a unique auto field ID. Every model comes with this. And the one we gave it is text. So now we have a table that we can add to our database with two columns in it. And let's go ahead and run Python managed dot py migrate. And this is going to apply that migration. And now we don't see anything happening at this point in time. All we see is that applying feed 001 initial was OK. That's all we need to know. That's about as much database management as we're going to get into in Django 101. So let's rerun him Django run server. And when we go back to our browser here in our admin, we're not going to see anything. And that's because by default, this table exists. But it simply is not manageable yet. So we need to make this manageable. So we created a model which maps to a table. We ran them migrations. We now need to go into feed admin dot py, and we need to register our model here. So let's go ahead and get rid of this comment. And this is going to look like this class. Post admin or whatever you want to call it, admin, dot Model. Admin. And admin is just coming from here. We can simply pass. We don't want to do anything. We can give an extra parameters, extra features. We can enable all sorts of features. We're not going to do any of that right now. We just want it to be simply editable. Then we say admin, dot site, DOT register, post and post admin. And so what this is going to do is connect post with post Admin. Now post is not imported yet. We need to import that so we can say from and because this is in the same folder, admin and models are in the same folder. We can simply say dot models, import post. And when we register here, it's saying Connect post with this post Admin, which is going to inherit everything from admin dot Model admin. Let's go ahead and save that. Django is restarted. And let's refresh our Django admin here. And again, once again, I'm just that localhost port 8 thousand slash Admin. And now I have in my feed app posts and we can go ahead and create a new post. This is my first post. Save. Now if you look at this, this is post object in Django. Every time we access a piece of data or a row in our database, it's called an object. And so we want to change this object name because it always just says the name of the model object one, object to object three. We don't know how to identify that. Let's go ahead and make it identifiable. So in our models dot pi here, we can say def underscore, underscore string. This is a class would always takes self as its first parameter. And then we're going to say return self.age. And whatever this post is going to be, that's what this object is now going to be called. So Django is restarted. Let's refresh this page and we're going to see this shows up with my actual text in here. So we've given this object a name, and this is just good for the admin when you're sort of debugging stuff or adding content through your admin. We can click it. We can change it, updated, save and continue editing. We could delete it if we wanted to. Let's go ahead. Yes, I'm sure it delete this post. Let's go add another one. This is a new post. Save. Now, here's the thing. A lot of people think that just because we created this, this object, that it should show up on our page, and that's simply not true. All we did was create a piece of data in our database or we provisioned a table in our database. We added a row into that table. So think of it like a spreadsheet. We have this giant spreadsheet, and that's our new table. And then we have two columns in there. In our little metaphorical spreadsheet here we have two columns. We have one called ID and one called text. This one is an integer field. And this one is a text field or a char field, a character field. So it can't have 10 thousand characters, but it can have a 140 characters. And we call that a char field or a character field. But where people get a little bit confuses, it doesn't show up on here. And that's because it's simply doesn't know how we want it to show up. How do we want to style our website? Where do we want to place the stuff? No framework in the world can tell you that it's not going to know automatically. You need to tell it explicitly what to do. So in our next lesson, let's go ahead and add our first view and update this a little bit. 6. Your first view: All right, we need to add our first view and this is a little bit involved. And once we set it up, it's really nice to use. But to begin with, it can be a little bit tricky. So our site comes with this file, not this one, that's the wrong one. Urls dot pi m. We can read through this. I would definitely recommend reading through that. I'm not going to read through that for you just because that's obviously a waste of your time. And then we have these things called URL patterns. And URL patterns is going to match some sort of path to some sort of logic. And for us, that results in localhost port 8 thousand slash Admin. Now we can change that admin if we wanted to, by changing it to my admin or literally anything else we want. I'm going to keep it as admin just for the sake of keeping things simple. But now let's say we want to add a new homepage. We need to overwrite the one that jangle gave us and Django gave us this one right here. We don't want this anymore. It's nice. Don't get me wrong, but we wanted to see something else. We want to make this our own application. Now, our application is going to look really ugly and then we're going to make it look really nice. So we're going to work on the backend first and then we're going to add the front end later. So we need to add some URLs in here. Now it doesn't really matter where we start. We need to do a bunch of things sort of at the same time. So what I'm gonna do is in this folder here, I'm gonna create a new file called URLs dot py. And that's just going to live beside my models up high and my admin dot py. Now in here we're going to be doing a few different things. So first of all, let's go ahead and say from Django, dot URLs, import a path. And we saw this in the previous file, Django URL's import path, and we want to use something like this. Now we're going to create our own URL patterns, and this is simply a list of paths. Let's go ahead and also give this an app name and this is going to be used for name spacing will talk what namespace and little bit later. But for now, let's just, let's just go with it. We're gonna give this an app name called feed. Then we're going to give it URL patterns is equal to a list. And this is going to take a path. And we just want the homepage. So we're gonna give it an empty path. And this is going to make sense in just a second. Then it needs to render some view. And that's going to be our template. And we give it a name. Let's call this index are like our homepage or something like that. Now when it comes to rendering some view, we need a view to render we're going to use in class based views in this course because that's the proper way to write Django, at least in my opinion it is. We can write function based views or we can write class based views. I'm gonna teach you the professional way in this course we're going to use class based views. Function based views are easy to learn, but it's easier to learn class-based and then functions rather than functions and then class-based. This needs to come from somewhere and we need to create some sort of view. So let's just, let's not save us yet, but let's keep this open and let's head on over to views. And you can see that it's already importing Django shortcuts render. We can honestly just ditch that because we're not going to be using a function based view. We're going to use a class based view. So we're gonna go to or not go to BUT import from Django dot views dot generic, import a simple template view. And then we're going to create a home page view. So we're going to say class home page view. And this is going to inherit the template view. And we're gonna give it a template name. Template underscore name is equal to home.html. And this is telling Django look for a file called home.html. And that's all we're gonna do. So we're going to save that file now. Let's head back over to URLs dot pi. And if we do from, because this isn't the same folder here, all of these are in the same folder. We can type dot views import. And what was that view called? Home page view. And then we can say, and here homepage view dot as view. And this is going to render our logic for us. It's going to make our view actually work. Now, this is all well and good. But you've probably noticed that Django hasn't really been restarting lately. So let's go ahead and open up our mysite URLs dot py and adding new URL pattern in here. Now in here we can prefix our Homepage if we wanted to. So we can make everything go to my slash home slash than a page, just like we did with the admin, but we don't want that. We want this to be the homepage, so we're going to leave this path blank. Then we're going to say include and we'll worry about these important just a second. Feeds URLs. And let's give this a namespace of feed. Now, feeds URLs and include don't exist yet, not in this file at least. So we have to make them exist. So let's do from dot URLs, import include. And let's also import our views and our views, but our URL patterns from our feed. Let's do from feed import URLs as feed URLs. And so we're just changing the name. We're importing URLs as an entire module. So we're importing this entire file here. Then we're renaming it to feeds URLs or feed URLs. And then we're going to simply put that any, let's go ahead and save this and watched Django restart. And we're going to see I have a typo somewhere in feed URLs. On line one. It is not Django dot URL, it's Django dot URLs. And let's go back to where it says an error here. And this is nice. This is just, we're debugging at this point. And this says path feed URLs is not defined. And that's because we said feeds, URLs. Feed is singular. Okay, cool, Cuckoo, cuckoo, cuckoo, Cool. That's all working. Let's head on over. Back to our browser and let's refresh. And we get this error. Template does not exist. Now where do we put this template? Django is going to look for this template in a few places. By default, it's looking in my Pip env here. And then it's going to look in Django Admin templates home. Django contra off templates home. We don't have access to those. Those aren't folders that are in our project. So we need to tell Django to use templates somewhere else. And we're going to create, in the next lesson, we're going to create a folder called templates, and we're going to tell Django to register it as a place to look for our templates. So for now you should have all these URLs. This does get a little bit tricky because we're using URL patterns in my site. We're also using URL patterns in the URLs file. Under our feet app. They're both called URLs dot pi. This is a naming convention. This is where it gets a little bit tricky is frameworks like they're naming conventions. We have an app named feed. It matches our app up here that is also being used in our namespace. So it's all the same right across the board we'll talk about namespaces in our templates a little bit later. Then in our views, we simply created a homepage view and then overwrote that nice Django View to give us an error. And once you see that error, you're ready to move on to the next lesson. 7. Setting up your templates folder: All right, in the last lesson we got this error. This template does not exist at slash n is looking for home.html. Now we know that it's looking in places that we don't have access to. And so we can go into this folder Users Caleb Delian dot logos share Virgil owns Django 101, yada, yada, yada, yada, yada, slash Django, contra off templates. Ohm, that is just a nightmare to deal with and there's a better way to live your life. And so in this lesson, that's what we're going to do. We are going to tell Django, Hey, there's a better place to look for templates. So what we need to do here is we need to go into VS code that's close that down. That's not relevant in this lesson. Let's close up feet and let's go into our settings.js and inner settings dot pi, we have this thing called templates. If we scroll on down, we'll see him templates. And it's looking for directories. And so what we want to do here is create a templates directory. So I'm gonna give this a variable called template dire. And this doesn't exist yet. We have to make it exist. Template Dyer is equal to. And at this point in time, if you don't remember this, if you're setting up a project, let's say a year from now, you can always just Google this, this part is all over the internet. It's easy to find this particular way of enabling certain template directories. So we do OS dot path, dot join, our base dire. And we're going to give it a folder called templates. And that's supposed to be base dire. And let's see if we can find based dire. Where are you? There it is at the very top here. And so that's looking for the path of this particular file is resolving it parent, parents. So it's moving up. And that's going to give us our project-based that's right in here. And then it's gonna create a new template or a new directory called templates. Now we used OS and so we need to import OS. So we say import OS at the top of this file. Let's go ahead and see what to Django is complaining about now. So we're getting the same error, but you notice it says that it can't find it because it's using a loader. It can't find it in templates, home.html. Let's go ahead and add that in. All we have to do now is create a new folder called templates. And in here we can create a new file called home.html. Let's just leave this blank. Nope, I lied. Let's say HelloWorld and let's make this an H1. So it's going to be HTML enabled. And let's refresh our page. And it says, hello world. If this does not work for you and you've done everything correctly, kick Django, just cancel Django and restarted sometimes and not often. But sometimes you need to manually restart Django when you're developing using Django. And so now we have something in here, we have something we can work with. But let's go ahead and right-click and Viewer page source. The only thing it says in here is HelloWorld. And it's got an H1 and closing H1 tag and that's fine. But what if we wanted to have a title on our page currently there's no title. Or what if we wanted to say that the language was the language was English or that this page was supposed to be responsive by default. Well, currently what we have to do is HTML colon five hit tab and it builds this page out for us. Hello world, save, refresh your source and we get all this stuff. But what happens if we have another view? Then we have to copy all this. We have to copy all of that stuff. Overwrite the title, overwrite the body, keep everything else the same. And what if we wanted to add a new metatag to all of our pages in the future. Well, we may or may not want to write that over and over and over again. Now if your site is huge and let's say you have like maybe a 100 different views. You're gonna have to copy and paste out a 100 different times in a 100 different templates. That's painful, that's no way to live your life. There's a better way in a better way is to use this thing called a base template. So let's go ahead and just undo this. And actually I'm going to delete that entirely and I'm gonna create a new file in here in the templates directory. And I'm gonna call it base dot HTML. And in here I'm going to give it HTML colon five image sharer stuff in here. And when we go back to our page, we see nothing. That's proper. We don't want it to do anything. It's trying to render this home.html, not base dot HTML. Because if we look at feed, views were saying, look at the template called home.html. Currently it doesn't know about base dot HTML. It's in our project, but Django is not aware of it yet. And so what we can do now is write extends, base dot HTML. And that has to be a string. And so we use a curly brace percent sign the keyword extends. And then in here a string called base dot HTML that matches the name of our base dot HTML file here. And then percent sign curly brace. And that closes that logic. Let's go ahead and refresh. And it says stuff in here. And if I go back to the source, it's all in here. Now. That's cool and all. But if we actually wanted to change anything in home, let's say this is my new homepage. This simply is not going to show up. It just doesn't, it doesn't know what to do with it. And so in the next lesson, we're going to talk about blocks and how we can basically write a little bit of code in our base dot HTML file and simply inject stuff into it. And so you think, you can think of it as like you have a piece of paper and you have a hole cut in it, and it's just a circle. And then you have another, certainly have another piece of paper, but it's cut in the shape of a circle. And so you put that one piece of paper into another piece of paper. Like when we were kids, we were playing with blocks and we're trying to fit the square and the square, and we're trying to fit the triangle and the triangle. That's exactly what this does. And we're going to learn about that in the next lesson. 8. Using template blocks: Alright, in the last lesson we talked about sort of fitting shapes into shapes and, and, you know, trying to replace the stuff in here we have a base dot HTML file. And home is then extending from base dot HTML. But it's not actually doing anything other than pulling in all this stuff and we want to be able to replace some of it. So let's talk about this notion of blocks. And so a block looks like this. It's a curly brace percent sign block and then a name. And we're gonna give this a name of body. Sometimes you see the name body, sometimes you see the name. Content. Doesn't really matter what you name it as long as it's consistent across your application. And then we say end block. And that's all we're going to do in our base dot HTML. Let's close up views, let's close settings. We don't need those and in our home.html, we do the same thing. Block, body stuff in here from home.html and block, and look at that interesting syntax. Django templates use two forms of symptom syntax. The use a curly brace and a percent sign. And this basically says executes a more advanced logic. Or if we really just want to print stuff, we use what I call a double mustache and we use two curly braces side-by-side and then close them with the opposite curly braces, will talk about those in a little bit. But for the time being, let's refresh our page and we see it says stuff in here from home.html. Let's refresh our source code. And it has all of this stuff in it now, plus our content from home.html. Now what's nice about that is in our home.html and our homepage. We don't have to write all this junk. All we need to do is say hey, Django. When you render this template, grab base dot HTML, read it for us. And then Django says, okay, yeah, yeah, I got that. I got you. I'm reading base dot HTML, but hey, by the way, there's a blocking your cold body. And so if you want to, I can put some extra stuff in there for you. And we say cool, cuckoo, Cool. Yeah, we actually do. We have some extra stuff. We want to replace your empty body block with some of our own stuff. And that is literally all we did. This is our home page. And when I refresh, says this is our homepage in our source code, come back here, and this is our homepage. So now we are actually working with a couple different templates. The nice thing about this is we can change one thing in our base dot HTML. And if we simply say extends base dot HTML from our home or any other template in the future. Every template will inherit that code. So we no longer need to worry about writing the same headstone every single time, or the same HTML declaration or the HTML tag. We don't have to worry about any of that. We can just do it once. Now as another example, let's go ahead and let's write a block in here, block, title and block. And we're gonna see that our title goes away. There's going to be anything in there just as localhost port 8 thousand. And in our home, let's do block title, homepage and block, and let's actually call it something way better. Maurice, super awesome homepage. Refresh. And it says my super awesome homepage. And again, all they did was say, Hey, there's a block title here. We're extending from base dot HTML. There's a block title here. All we really did was say, hey, grab this code and it's like COP copying and pasting it in here. It's like that. Now I'm just gonna undo that. And one more thing we can do is we can give default content in here. So default title in case I ever forget to add the block title in a template. Let's say, whoops, caled forgot to add that in there. Let's refresh our page and it says default title. So if we don't overwrite it, we now have a base in here, a default. If we do overwrite it, it's then going to use whatever we used instead so it save that refresh and it says my super awesome home page. And that is how we use blocks. That is literally all there is to a block. It is simply like that metaphor I made in the last lesson. When we were kids and we had those little toy zone. It was like, here's a circle fitted into the circle or here's a square or a cube fitted into the shape that looks like a square or a triangle. That's literally all this is. This is R cube. This is r squared. We're just fitting one shape into another. 9. Custom page context: Alright, let's talk about adding some custom context to our page because right now our homepage is cool, but honestly it's hard coded. There are no variables whatsoever. There's no way to add any custom logic to this thing. And so at this point in time where we really just have a really fancy static website. It's using Python, it's using Django, but it's static. There's no dynamic content to it. So let's go ahead and talk about this thing called context. So let's close our base dot HTML because we don't need that anymore. And let's open up our views and dot py. And in our homepage view, we can have a method in here called getContext. It's a method on a class, so it always take self as its first parameter, and then it takes keyword args. And then basically we're working with this thing called context. And to what context is, is we can add data in here from Python custom Python logic. And then we can throw that into our quote unquote context and use it inside of our page. So we're going to quickly whip through a little example here and then I'm going to show you exactly how I found out that getContext data even exists. How, how does this exist? How do I know that this exists? I'm going to show you how I found that out. So I'm gonna do context is equal to super, and that's going to go up to the template view dot get context data. And we'd never pass in self, but we can pass in our keyword, args are quarks, and we simply, simply return context. In here. This is basically a dictionary. We could say, My thing is equal to hello world, smiley face with a tongue hanging out. Hope world, Hello World. This is dynamic. Django restarts. And what I can do here is I can take this, my thing, go over to home.html. And instead of reading, this is our homepage because this is simply a variable. We, we don't want to do any extra logic with it. We're not writing a four-loop. We're not telling Django to fit a shape into shape using a block. We're not doing any of that. We simply just want to print something out to the page. We use the what I call double mustache syntax. So a curly brace, curly brace, then some stuff in the ending curly brace, curly brace. Now inside of here, we simply say my thing and that my thing is coming from right here, my thing. Let's go ahead and refresh our page. And it says, hello world, this is dynamic. Now in our template, it doesn't say that, but in our view it does. So now we can have some form of logic and this is starting to get a little more dynamic. Now this is still not a great example and we'll work with this to make it a better example in the future. But right now, this is a decent enough example of how we can basically perform some Python logic. Put it into a string or a number or anything we really want, and then access it in the template. Now I mentioned, I was going to show you where I got getContext data from. And there are a few amazing Django sites out there. One of them is called CC BV, classy class based views. And so it's CC-BY v dot CIO dot UK has got different Django versions. And here we're using Django three, so it's automatically selected. And I'm using a template view. And where I get that from is this template view. And all it's doing is rendering a template. It's not doing anything extra. Theres a lot of different views in here. There's a login view, Logo, do detail view, all sorts of stuff. We're gonna be working with a few of these in Django 101, but right now we're only working with our template view. So I click on template view and it tells me what kind of content type it can be, extra content HTTP method names. So is this allowed to have a GET, post, PUT, patch, delete head options or trace HTTP headers. Honestly, we're only using get. So you could set this to just get a response class template engine and a template name. Currently we're only using the template name because everything else is automatically done for us or handled for us. And what I like to call it because it's sort of magic is automagically handled for us. And then we have these methods. And we have as view which we've actually used, believe it or not, in our URLs dot py, homepage dot as view. And we can see what as view is doing. And it's doing all of this stuff automatically for us, so we don't have to write that. Dispatch is like our init method almost it, it runs basically right after init, more or less that's true. And we have one in here called getContext data. And I just happened to know that context is what we call it. And that's because I've read through the Django docs a few times and so I'm sort of familiar with that notion. If you haven't read through the Django docs, definitely spend a little bit time and read through the Django docs whenever, you know, whenever you have an extra five or ten minutes, there's a lot of docs, so it's gonna take you a long time. It's it's not something you can read in an hour. And the dogs are pretty well-written. So getContext data's doing this. It takes self and keyword args, which is do, do, do, do, do, get context data. Self. Keyword args is gonna do quarks that set default view is equal to the self. If self.contents is not none, do some other stuff otherwise, return the keyword args. And we basically said, yep, cool, whatever Jack was doing, let's do the same thing. So we grabbed our context by using super dot get context data, passing those same quarks that are being passed into us. Added a little bit of context and returned to the entire thing. So in the future when you're learning, you know, a little more advanced Django. You can always go to CC-BY V and Doo-doo-doo-doo, just waiting for this to load. There's all sorts of stuff in here. So feel free to take a little browse through this. But for the most part we're just gonna stick with something basic for now as to not overwhelm you. In future lessons, you might even see me reference CCB v, Just because honestly it is a great resource to have end. It tells us things like, like, like, like when we're using get context data, does it accept a request? Does it accept args? Does except only self and quarks. What does it accept? We don't know, and we might need to know that when we use super. And so this is a really good reference for that. In the next lesson, let's go ahead and display our posts on our home page. 10. Displaying dynamic posts: Okay, in the last lesson we talked about getContext data. And we added this thing called my thing, and it's simply a string. My thing is a string at rhymes. And I didn't mean that to rhyme nor more rhyming. And I mean it would anybody like a peanut little movie reference there if you're a movie buff from The Princess Bride. And so we're going to go ahead and swap out my thing for posts. And what we want to do is we want to get our models. We have these posts and we did this in like the first couple of lessons. Whoo, that got way too big. We have these posts in here, so I've got this one post in here. Let's just go ahead and save that, add another post. This is a second post. Save at a post. This is a third post save. And now let's actually make the show up on our page, because right now nothing shows up. And so what we want to do is we want to grab these posts and get all of them. And so what we can say here is contexts, posts is equal to post and I'm getting that name from this class. We haven't imported it yet, we will in just a second. But this class name dot objects because surprise, surprise. Basically everything in Python is an object. And in Django, they're still objects. It's written in Python, so everything's an object dot all. And that's going to get all of our posts for us. Then we can say from DOT models import post. And that's simply going to allow us to grab this post, pull it into our views dot pi. And then when this page is rendered, it's going to say execute getContext data, do whatever Django does. And there's a variable in here called posts. And it's going to be all of the posts. And so let's go and swap out my thing for posts in the template. And we are simply going to for now for the time being, use double mustache syntax. Let's go ahead and refresh this. And we see this weird thing, this thing called a query set. And so in a database when you are looking for data, it is called a query. And we have a set of a query here. So we've got our first post, and this is a new post, second post and a third post. And this is somewhat of a list. This is a really, really fancy Django list. And so we can loop through these now. And so instead of writing posts, what we can do is let's get rid of this H1. We don't need that in there. We can say for posting Posts. And four, show me a thing. Let's put a horizontal rule in here. And this should show three times. Show me a thing, show me you show me a thing. Now this is, let me fix that indenting cuz that's gonna drive me nuts. This is looping for every post. And we know that when we loop through every single piece of data in a list, we have that exact item. And this is just like looping through a list in Python. The only difference is this list comes with extra stuff. So it's like looping through a list of dictionaries. And so now we have post and text. And so we can do postdoc texts Enter template. And so let's go ahead and write post dot text. Refresh your page and says, let me zoom in here. This is a new post, this as a second post. This is a third post. Let's go ahead and add one more in here. Let's make that smaller again. And Doo-doo-doo-doo, This is a fourth post, save. And when we refresh, boom. Now we have data being put into a database and data being pulled out of a database and rendering in a template. This is literally all we need to do for this particular lesson. In the next lesson, let's go ahead and add some images here. 11. Adding images to your model: Alright, let's talk about how we can add an image. And so we can do a few different things. But we're, we're going to sort of bypass some of the intricacies. And we're going to work exactly in our models, dot-dot-dot. And so Django gives us this thing called a model is.5 field. And we can upload any form of file. But that's not quite what we want. Because maybe we want to have some thumbnailing and stuff as well. So what we're going to do now is install a new package. And we're going to use that package. So I'm going to reference the docks right in front of you, and I'm going to show you exactly how I do it. So I'm gonna delete that, go back to my browser and type in Django thumbnail package. Django thumbnail, and that's not what I typed package. And there's Django thumbnails, there's Sorrell thumbnail. I've used soil thumbnail once or twice before it. Apparently I've clicked this to, to, to, to do so let's take a look at our docs here. Features at a glance supports Django 3.1. That's what we're using, that's important. Python three support, very important. Storage support, that's good. Plug-in Engine supports, pillow image, magic, pill, wand, all sorts of things. These are all good things. If you don't know what those are, that's okay. Admin integration with possibility to delete, dummy generation due to, due to do all sorts of stuff. Do we have thumbnailing and cropping alternative solution, alternative resolution versions of a thumbnail margin calculation for vertical positioning. This list looks promising to me. And so how to use the code pip install Sorrell thumbnail. So let's grab that. And in our virtual environment I'm simply going to paste pip install Sorrell thumbnail. And if you're using Pip env like I am, we should be using pip install several thumbnail either way and we can still do Pip show sorrow thumbnail. And that shows us that we're using Version 12.7, 2.0. what else do we have to do? We need to put soil thumbnail in R installed apps. Let's do this. Where are we here? My site settings installed apps. We're going to scroll down. Let's just throw that somewhere in the middle, like that. And then there's some usage in here, but we need to actually add it to our model. Here it is modal usage. We wants to follow this. So let's go back to our models dot py. And what do we see here from Sorrell thumbnail import image field from Sorrell dot thumbnail, import image field. And in here we can say image is then equal to that image field. And so now we're using a third party package that layers on top of Django, which layers on top of Python to basically create an image field. So we can upload images and then thumbnail them nicely in our template, Django doesn't come with this by default, just because Django is quite bare-bones, it gives you the bare minimum and lets you extend to do whatever you wanted to do. It's not meant to have every solution built into it. It's not designed that way. And the reason for that is because if you were to create a website that didn't need. Sorrell thumbnail and it came with oral thumbnail. That's just loading extra stuff, that's extra stuff to download it, it's just not worth it. And so Django says, yeah, other people can build these extensions. So we added this image field in here. Let's go ahead and run, run server. And it says, look at this feed, that's our app, posts, that's our class. Image, that's our field. Cannot use image field because pillow is not installed. Hint, get pillow at or run Python dash M pip install Pillow. So let's do that. Pip install pillow with a capital P. Okay, that's done. Let's run Django again. We have one on applied migration. Let's do Python managed up high migrate. And this is applying our thumbnail initial. Cool, that's from our third party package. So it's provisioning a little thing in our database. Let's see if we can make our new migrations because we need to make new migrations. So these migrations that we just ran came from Sorrell thumbnail. When we make migrations here, what we're saying is Django, hey, take a snapshot of what we currently have versus what we used to have. And if there's any changes in there, create a migration file. And so we have, we said this post class now has an image field on it. And so let's go ahead and run, make migrations. And this is going to say that the image field is not allowed to be null. We can either press one to provide a one-off default, or we can hit two. And let's set a default in models dot py. That's right in here. We can say something like default is equal to something. We don't know what the default is though. So let's go ahead and say one and see what happens. And I'm just gonna type one and maybe those breaks, maybe this doesn't. If it breaks, I'll show you how to fix it. And I'm gonna take the number one in here. So it created a new migration file called 000 to post image. And so if we click this, it has a dependency on the original migration file. So it needs that file. And then it's going to say for the operations things that should do, add a field. And that field is coming from soil dot thumbnail fields dot image field. It's a default of one. That's what we wrote to upload to. We didn't give it an upload to. That's just like a folder we get upload to if we wanted to preserve default false. And so basically this is going to give us a new column in our database. Let's go ahead and now run migrate. And so originally when we made our migrations, we simply made this file, we didn't execute it. Then we run migrate and it says, hey, Python, By the way, I want you to take this file and I want you to apply it to my database. So let's go ahead and rerun Django and see what things look like in there. Things so far look good. Let's head on over back to a browser. Oh, let's see if we actually broke anything. Okay, that looks okay. Fourth post currently set to one. That's not at all what we want, but we could change that. So what I'm gonna do here is I'm simply going to delete all of these because I want to add a new images. So I'm going to select all of them. Deletes, selected post go is going to say, are you sure? Yes, I'm sure. Add a new post. This is the first post. And let's add an image. And let's add an image of Galli, Galli to dot-dot-dot JPEG Open Save. And now there is a file in here and we can actually even click that. And it says, oh, no, this actually doesn't exist. And beyond that, if we look in here, let's close up all those files. Our image is in here. So let's say you had 10 thousand images. You now have a folder called Feed, the folder called mysite folder called templates, your database, 10 thousand images managed up high, Pip file, Pip file dot loc. That's no way to live your life. We want to put all of our files are media files. That's what we call them. All of our media files into a folder called Media. And that's what we're going to do in the next lesson. So right now we have an image field setup, not displaying anything on our homepage yet. We need to set up our media folder so that all of our images gets uploaded to one particular folder. And this is really nice if you ever needed to zip up all of your folders or all of your images rather, you can zip them all up quite easily. You could delete them all quite easily. You can work with them easier if they are in a folder. So in the next lesson, let's go ahead and set up our media folder. 12. Setting up your media folder: Alright, let's take a look at adding a media folder to our projects so that all of our images don't get uploaded straight to the root of our project. In order to do that, we have to open up my site settings dot py, and pretty much anywhere I guess, let's just throw it in here. We can write media URL, and this is just going to be the name of our folder. And it's going to be slash media with a slash at the end and at the beginning. Then we're going to write our media root. Media root is going to be OS dot, dot join, base dire. And then we type media without a slash at the beginning. And so this part here looks pretty familiar, doesn't it? We set that up with our template directory. But instead of using the templates folder, we're using the media folder. And our media URL is going to be when you're accessing content. When you go to my slash something, what does that folder called? Wherever that folder is, and then your image dot JPEG or whatever. So we need the setting, even though we're not currently using it, we need that setting. Then let's go over to our URLs dot py. And we need to write some interesting stuff in here. So we're going to modify this a little bit. So first things first we're going to need our settings. So let's do, let's first of all move this up so it's in alphabetical order. Just as a good practice from, import settings. And then let's also import this, this function called static from Dot URLs, dot static, import, static, not status, it's static. Then at the very bottom, we say if settings dot debug. And what debug means is, you know, when we didn't have a template and it said there is a template error and it showed us where it was looking for that particular template. That's what debugged does. Debug allows us to easily figure out what's going on. And in production when you launch your website, we actually turn this off so that people can't see all of that extra information because that will make your site vulnerable. But while we're coding it, we want it's enabled and it is enabled by default. Then we say our URL patterns. Let's add to this URL pattern. We're going to say static settings, media URL. And then the document root, document underscore. Root is equal to root media route. And so this is just using a pretty standard watts Python language. Really. We're importing settings the whole file. And then we're using the property in that file. We're just importing settings. Again, it's basically an object. And then we're using the media route and we got that from our settings in here, media URL, media root. So let's go ahead and save it and see what happens. Okay. It looks like nothing happened. But let's go and refresh this page and then change this image instead of gulley to, let's put delhi belly. Save that. And let's view it. And you can actually see slash media, gully belly dot JPEG. And let's take a look in our project here we now have a folder called Media and gully belly is in there. That's fantastic. We can now get rid of gulley too, because that was our original one. That's delete that. We don't need that anymore. And all of our folders or not or folders, but all of our files are going to be uploaded to the media folder. So as a quick recap, what we did was we added media URL and media root. And this is a lot like when we created our template or template path. Doo-doo-doo-doo, this one, our template dire. This one is our media root. And then we used a media URL and that media root in our URL patterns. And so the idea here is that when you serve static files with debug turned on, Django is going to serve those files for you. That's technically an insecure way of using Django. So when you launch your website at some point in the future, you don't want to be using that and you're gonna have debug turned off and your static files are going to break. Then you can use something like engine X to reverse proxy the images and set it up that way. We're not going to talk about that for, for right now, just because that gets to be a little bit more complicated and a little too overwhelming when you're just learning Django. But for now, this is what we need to get up and running. Just that. In our next lesson, let's go ahead and actually add this image to our home template. 13. Adding images to your template: Okey-dokey, let's add images to her home template. Because if we take a preview and we can close that. If we take a preview of our page, it's simply says this is the first post, but there's no image in here. Let's go ahead and add an image in here. And so we have to open up our templates home. And we know there's post-tax. And where I'm getting that from is models dot py post 2.txt. We now have an image. We can do Post.all image. So let's just print that out and see what that gives us. Let's do a BR in here, post dot image. Let's see what this returns for us. The name of the image. I could probably do post dot image, dot URL. Yep, there it is, that's the actual URL. And if I were to wrap this in an image, IMG SRC is equal to. We're going to see that this is a giant, giant, giant image. We need a thumbnail because this image is just so big. So big. Look at that cute face. And he wanted a smaller image because this image I know is already over three megs. And if we're to show like a 100 images, that's someone has a download 300 megabytes to view your webpage, that is simply unacceptable. So what we can do is now reference our Sorrell thumbnail docs. And how do we do this? It says Template usage. We want to load a thumbnail. So let's go back to our homepage and put load under extends. Extend should always come first and then we load. And then what do we rate? We say this is a simple usage. Okay, I'm just gonna copy and paste this to be honest. Doo-doo-doo-doo. And so this is going to use a thumbnail that comes from up here., image. We don't have item, we have post dot image, 100 by 100 and let's do 200 by 200 crop center as I m. And then we could say the image sources I M dot URL width as I m dot width, height is I m dot height. Let's go ahead and save that. And let's go back here. Simply refresh. And it created a thumbnail for us. Cool, so that's a perfectly centered 200 by 200 image. Let's go ahead and inspect this. And it created this weird URL for us. Let's open this up in a new tab. And this is the image. It's in our media folder. It automatically created a cache folder called BB C1, and then some sort of hash. And that's just simply using caching for us, so it doesn't have to regenerate the thumbnail every single time someone hits your website. So that's really nice. And the first time we loaded the website, you notice it probably took like 2.5th faster, 2.5th slower. Rather, when we refresh this time, it's going to be pretty much instant. We don't see a flash or anything. It's just boom, it's done loading. Let's go ahead and add a second post. So let's save that one. This is a second post. Let's add an image. Let's add rhubarb. Save, and let's refresh our pages. Get rid of our console here, refresh our page. Oh, look, there's rhubarb. Let's go ahead and add one more. This is a third post. And let's add a photo of rhubarb and gully. And this one's a big one. This is 4.2 megs. Thank goodness. We are thumbnailing. And there it is. This is all up and running for us. In the next lesson, what I would like us to do is be able to click one of these images and go to another URL somewhere and see the full image. 14. Adding a detail view: Okay, what I would like us to do is be able to click either this text or the image or both. And then go and see a different webpage where we show the full image, the uncompressed version. And to do this, we use this thing called a detail view. And so it's right in the name there, it's a detail view. We need to add a new view. So let's go into our feed, go into views. And let's add a new detail view. And this comes from generic detail view. And if you aren't sure where I got to detail view from or you aren't sure where to import this from because you don't have to remember all the imports. That just comes with writing Django and Python over time, you start to remember them. But if you don't know where it comes from, you can always go to C, C B v dot c o dot UK. And that will tell you exactly where it's coming from. In fact, I'll show you where it's coming from. We have a detail view. Where are you generic detail view. And it says right up here from Django dot generic import the detail view. And we can do all sorts of stuff in here. And so it has a content_type content object name, extra context. If we wanted to add extra context, HTTP methods, a model, we need to set that model. Primary key URL, keyword, yada, yada, yada, all sorts of stuff. We're not going to work with a lot of this. We're just going to work with some of this. So we need to create a new detail view. So let's do class. And let's call it Post detail view. And this is going to inherit from Jen goes detail view. Then we give it a template name. And that template name simply is going to be detailed layout.html. And that model is going to be post. And that post is coming from up here, which comes from our model here. And really all we're saying at this point is saying, you know, we have this model, we have as detail view. If you go to a particular URL, just automagically work for us, fetch that particular image for us, that particular post. And so we don't have to do a lookup. We don't have to worry about managing your database. Django manages this detail view for us and all we have to do is write the two lines of code. It is honestly a beautiful, beautiful thing. So I save that Django restarts, nothing happens. What we need to do now is go into our URLs or feed URLs. And we need to add another path in here so we can type path, let's say details slash some sort of integer that's going to be the post id. And render a view. And the name is going to be, let's just call it detail. And this should be more like that. So let's not do details ASU detail and instead of int, because that's just going to render my slash details slash int. We want to say I N T colon PK. So it's looking for an integer. And when it renders our view in here, it's going to be renaming that integer, whatever that is. So it could be like slash detail slash one is going to look at that integer and it's going to name it pk. Then we need to render a view. And that view is called post detail view. So if I go back to URLs and let's do from DOT views import homepage view. Let's also import the post detail view. And that's a class so we use as view. Okay, Django was not complaining so far. So, so far, so good. Let's go ahead and try this out just to see where we're at. So first of all, we need an ID. If I click this, it says the ID up here, posts is eight. So let's go into school to take a look at postdate. So we can now do our website localhost port 8 thousand slash detail slash eight. And something in here is roughly o. And that's because I put a slash at the end here, and there should be a slash right there. So just wait for Django to restart, refresh. And we should get a Template Not Found error. There is a template does not exist. Arabs looking for detailed layout.html. Now where's this looking? While it's going to look in our templates folder called detail, called detailed dot HTML. Templates folder is called templates. The file is called detail dot HTML. Or it's going to look in this package, or it's going to look in this package. So let's just give it the first place that's looking templates, detailed layout.html. So we go into our templates, new file, detail dot HTML. And let's just write hello world. Let's do nothing fancy here. Hello world with a heart. Now that's not gonna work. It's HTML with a smiley. Cool. Okay, we have a view being rendered here. This is good news. Let's go ahead and extend base. Because if I back up real quick, let's view the source. There's nothing in there. Let's go ahead and extend, extends. Base dot HTML. Let's refresh a page. It looks like nothing happened, but if I view page source again, we have stuff in here with a default title. So let's do block, title, detail, view and block. And it changed the title up there. That's good. That means this is working. Block, body and block. This is where my image will go. This is where my image is going to go. So what I'm gonna do is I'm gonna stop here. And in the next lesson we're actually going to fill out some of the details on this page. We're not going to make it look great, but we're going to fill out some of the details on this page. 15. Detail template: Alright, welcome back. This is our Detail page. This is supposed to show this image here, rhubarb and gully. Currently it doesn't show anything, nothing in here as dynamic. Now we know we can use getContext data, but we don't need to do that because Django manages a lot of that stuff for us. So we open up our views dot py. We're using a template name called detailed layout.html. And we're saying that model is post. If we open up our URLs dot py, our path is detail and then some sort of number. And it's going to automatically figure out that there is an integer in there, re-assign it to the variable called pk. And somewhere in this detail view, it's going to work that out for us. It's going to say, oh, I know exactly what you're looking for. Now by default, if it can find what you're looking for in your context, what would we call this? Because before we were calling it like posts or my thing, we need to call this something. And so let's go ahead and try object. And it gives us the object. And in fact actually what this is doing here, really glad this came up, is it gave me the text. And that's because if we go to the models and gave us the post object, but a give a, gave us the string representation of this, which is just self.tableView. But presumably we could do object dot text or object dot image. So let's do object dot image. Okay, that's the image name. So almost there. What if we did Image.all URL? That's our URL, that's what we want. So let's go ahead and hash this out a little bit. So let's say h3 text, object dot text. And let's do h3 image. And this is simply going to be an image tag, IMG SRC. Let's make this a little bit responsive. Will add Bootstrap later to this with a 100% height auto. And boom, there it is. Look at those QD bias. And so now we have a detail view. In the next lesson, what I would like to do is if we just click back, these aren't clickable yet. So we need to figure out how to make these clickable and, and where to go. Because we can hardcode this. We could in our due to, due to do our home.html, make this a link that goes to stash detail slash post-doc ID if we wanted to, because we know that ID column exists, there's a better way to live your life though. And what if we ever change it from detailed to details or image or some other prefix in our URL here. What if we wanted to change that? Well, then we'd have to change it in her home. And what I'm gonna show you a way that we don't have to do that. We can just basically say, hey, Django, handle this for us. And if it changes in the future, also change it here for us. So that's what's coming up in the next lesson. 16. Template links: All right, let's take a look at making these clickable and to another page. So first of all, let's close detail, views and URLs and models. We just need to work with our home.html. For this particular lesson, we need to create some sort of link. And so what we could do is a HREF View Details. And then in here we can say go to slash details slash post dot id with a slash. And when I click this o c, This is exactly why we don't do this. It's not details. I keep you in that its detail. Refresh. Go to details. Okay. That works. And that works. What if for some reason I changed it from details to info? Okay, so I'm gonna go back to my homepage now, refresh. My page is no longer going to work for me. And you can see it gives me a fluorophore. So something broke. Now there's a nicer way to do this. We gave this a name and there's this namespace in here. And in that namespace also matches. Where are we might cite URLs that namespace matches here. So we can say in our home.html, we can say, hey Django, execute the function called URL. Then look for our feed, that's our namespace and our detail view. And I'm getting that from namespace, that's our app name, detail view, that's our name. And then it takes an integer. And so as a string with quotations or apostrophes around it. And then outside of that string, I simply say Post.all ED. And let's try this out. If I click this, it goes to detail slash six. Let's go back to our URLs and let's change this to info. Refresh, wait for Django to restart. Refresh that. Click this again. And you can see my links changed and the URL goes to info slash six. And it automatically generates it for all of these images for us because it's in a for loop. So now I'm just gonna undo that because I like it being called detail. But now we don't have to worry about like hardcoding URLs, which is really, really nice. Let's go ahead and make this entire thing clickable. Let's do this. Slash a. And because this has some stuff in it, let's do style, display, inline, block. And this whole thing is now going to be clickable. So now we can go and see gully, Look at this cutie pie. Kind of chubby, kinda cute thing, this cutie pie. And we can come back here. Now, what if we were making some sort of app, like, like almost like a mobile app. And we wanted to link up here that says go back. We could throw that on our Detail page as well. So let's open up our detailed dot HTML and inner body. Let's add a link, a HREF. Go back, slash a, and let's add an arrow, a left arrow. And in here we can simply say curly brace, percent sign, URL, feed. And I think we called it index. We're gonna double-check in just a sec. Feed also matches the namespace here, so we're using feed here and then do Doo-doo-doo-doo index. Now this doesn't have any sort of parameters in the URL, so we don't have to worry about passing in any parameters. Unlike when we use the post detail view, we said use feed colon detail. And then we passed in a parameter. This one doesn't have a parameter. This is just the homepage. There's no parameters to pass in. And so we use feed colon index to go ahead and refresh our page. And it says Go back and it's gonna take us back to our homepage. It's just gonna keep working for us. Just keep working. And that's how we add URLs. In our next lesson. Let's go ahead and add a form so that someone can upload an image on their own. And they don't have to have admin access. So anyone can visit your website and upload an image on their own. 17. Adding an upload form: Okay, let's have a conversation around this idea of forms. So if you come from like a Node.js background, you may or may not use actual forms, but is the proper way to use any sort of form where you upload data or you save something is to actually use a form element that is the proper way and that's the way we should all be doing it. New progressive web apps and single-page applications often skip this entire process. We don't do that. And that also keeps our form nice and accessible. So if someone isn't running JavaScript or using an old browser, it's still going to work for them. So in my opinion, this is sort of the better way of doing it. You can always later JavaScript on top of it to make you form really fancy too. But for now, let's just take a regular form. First things first in our feed, let's go ahead and create a new file called forums dot pi. In here we need to do from Django import forms. Now this is going to look a lot like from Django DB important models, class something models dot model. Check this out. Class post form. That's what we're going to call it, forms, dot form. And that's pretty much all we have to do to create a form. Now we can give it some sort of parameter, are not parameter but a field. What kinda stuff do we want to display in this form? And we do this with like text is equal to forums dot char field. And unlike our models where we do models dot char field, we do forms dot char field. Let's also add an image in your image is equal to forms dot file field. We're going to upload a file, whatever that is, we're just going to upload it. We're not going to worry too much about image validation or anything like that. We're just going to simply upload an image or upload a file and hope that as an image because this is jangle one-to-one course, we're not getting into the nitty-gritty and complexities of Django. We just want something basic that works, that gives us a little bit of experience. So we have forms dot pi with a post form in here. Let's open up our URLs dot py, and let's create a new path. And this is going to create a new page for us where someone can actually post an image. And let's call it Post. And then it needs to render of view. And that name is going to be, and this is called add. We're going to add an image or no, let's stick with post. They're going to post a new image. Now it needs to render a new view. Where are we going to get this from? Let's go create it. So first things first, let's, let's just name it here. Add post view, dot-dot-dot as view. We're going to use a class based view for this. And let's import that Add Post view. And when I hit Save, you're gonna see that Django has a little bit of a freak out. Yep. Cannot import Add Post view, yada, yada, yada. We know it doesn't exist yet. Jangled, thanks for letting us know. So let's go into our views and let's create a new one in here. Now, we want to import. A Form View. And what this is going to do is this allows us to post to our page to actually upload things. So let's go ahead and create this new view. Class, Add Post view. It's going to be a Form View. Now what comes in a form view? We don't know. So let's go back to CC-BY v. Let's go back to the homepage. And where is our form view? Right there, generic form view. And so this takes a template name as well. This takes a form class. Where are you? Form class? And nice one. And I think it's always going to look for it is a success URL. So when the form is successfully submitted, let's say there weren't any errors in it. Let's say it was successfully submitted. Where's it's supposed to go? And there's also one method in here we really want to work with, and that is our form valid. If this form is valid, what is it going to do is going to give us an HTTP response redirect to the get success URL. Let's just follow this. Gets access URL. If there is not a success URL, which we are going to set, but if there wasn't one, it's going to say improperly configured, otherwise, it's going to return that success URL. So let's go set up our view first. We need to give it a template name and let's call it new post.html. We need a form class and that's going to be something we aren't sure yet. And a success. Url, at least S access URL. And let's just make it go back to the homepage. Now that form class, what is this going to be? This form class is going to be post form. And so we need to do from DOT form's import post form. Scroll back up to the top from forms import post form. And we can change this down here to post form as well. And look at that. Django isn't complaining anymore. If, if, if, if, if if we go back here and go to What was that URL slash post. Today, template does not exist. We've dealt with this twice. Now. We know how to deal with this. We simply need to make it exist. So what I'm gonna do here is not base detail. I'm just going to save this as new post.html and just overwrite the content in here. Upload a new image is going to be the title and the body is going to be nothing yet. It's just going to say empty. Boom, just like that. So now we're making views pretty quickly. Now we have to actually render this view somehow. We have to, we have not the view, but the form. We have to make this form actually show up. So let's get rid of base, let's get rid of models. We have this Add Post view. What can we do? What does CCB V tell us? Let's go into get context data for mixin. And if we read this right, if form not in quarks, then quarks form is equal to get form. So we know that this isn't a context. We can write form in our page. Let's go ahead and write form right in our template. Let's see what this does. Form. Hey, look at that. That's not bad at all. And there's a few different ways we can do. We can do form dot ASU L. And if we right-click and inspect, it gives us that, well, this is a table as well as p, better. As table as UL. There we go. As you well, I don't know why it showed up as a table that first time. That was kinda bizarre. I think that might have just been old source code we were looking at. But as UL is going to create a list, and let's check this out. We now have a form. Now this isn't going to do anything. If I go in here and hit Enter, There's no form. And if we check out this source code, we just have allies in here. And actually what I'm going to do is I'm going to use as p x. I don't want to deal with lists yet. And so simply puts them on a new line. Cool, cool, cool. But we need to add an actual HTML form in here. So Django lets us control by letting, by just giving us the insides of the form. We can write what we want on the outside of the form. So the for method is going to be post and the action is going to be it's own page. Then let's create a new div in here with a button. And the type is going to be not button, but it's going to be Submit. Submit form, slash form. Let's check this out. Let's get rid of that page. Check this out. We have a submit and let's try this out. And I'm going to show you that this is actually going to fail. First of all, it's looking for this thing called a CSRF token. And this is a cross-site request forgery token. And basically this make sure that people are submitting the form from your website. And we add one of these very easily by doing curly brace, percent sign, CSRF, underscore token. Let's go ahead and try this again and let's refresh the page. Blah, blah, blah, blah, blah. And image in here. And we're going to see that this also fails. It says this field is required. Go ahead at another image. It says this field is required. Again. What's going on here? We're adding that in there. Now here's the thing is when you upload images or files of any type, any type on a form, you need this thing called an ink type. And we do multi-part slash form data. And this allows us to actually send files from our browser to the server. Let's go ahead and save this refresh. Oh, we don't want to do that. We want to do a hard refresh. This is a new photo. Let's go ahead and save this or not save this, but let's add that. I scan this image here. Okay, a set me back to the homepage. That was the request or the request, but that was the success URL that we wrote that came from, where are we here? The success URL went straight back to her home. Now if we go back to our admin here, let's check on our posts. Are post doesn't exist yet. We need to add a form valid posted here and create a new post with the data. So we have this method called def form valid. It takes self and form. Let's go back to CC-BY V and Form valid right here. And what is this going to do? This is going to return an HTTP response redirect to the success URL. So unlike our context data where we did context is equal to super. And then a bunch of other stuff we're not going to do that. We're going to do return super dot form valid with a form in there. And let's make that lowercase. And then we can say in here, print, this was valid. And let's just like spam or terminal with this. And let's go ahead and go back to slash post new image. And again, this is not going to save yet. And there is, there is an easier way to do this. We could use a model form if we wanted to. We're not going to do that just yet. We're gonna, we're gonna keep it simple with a regular form. So let's go ahead and submit this. And we're gonna see that our terminal has a little bit of espouse attack. It says this was valid over and over and over again. The form itself was valid. Now if we want the data from the form, we can always do print form dot cleaned data, that's the validated data. So if someone tried to write HTML or JavaScript or anything in there, it's going to clean it for us, which is really nice. Django just handles that for us. Text. We could just print that a few times. Let's go back to slash post will add a URL for this pretty soon. This is my text where the heart. And it looks like it did nothing but says this is my text with the heart. And so now what we can do because this form is clean, we know that form dot cleaned texts with text as a dictionary key prints the text that was in the form. Presumably the image is also going to work. So if we go back to forms, we have text is equal to forums dot char field, and image is equal to forms like file field. Let's go ahead and create a new post. So we need to create a new post. Now before we do that, we have to make your post is in fact imported, which it is. And then we can say the new object because everything's an object is equal to Post.all objects dot create. And if we take a look at our models, it's looking for text as a keyword and image as a keyword. So now we can say text is equal to forms dot cleaned data text. And the image is equal to forms dot cleaned data image. And then when it's done, when it's done saving this, it's going to send us back to the homepage. Let's go ahead and see if I made any mistakes in here. Slash post. This is my newest image. And who lets do friends Lego set. And says, oh, names form not to find okay, that because where you, it's not forms its form. And the reason that it's form is because it being passed in here as the word form, as the argument form. Go ahead and try that one more time. And a nice little thing we can do here is if you see something like this, you can just refresh your page. And it's gonna say, hey, because this was a post method. Do you want to try again? We're gonna say yes, try again. Scroll on down. And this is my newest image. This is my Lego set that I made last weekend. We'll set a friends. Last but not least, we need to add a link to this actual view. Otherwise, people aren't gonna know that this exists. So let's go to our home view and let's add a link. A href is equal to add a new post. And let's do a right arrow. And this is going to go to URL feed posts. And where I'm getting that from is again, feed, that's the app name, that's the namespace we're using and the name post. So it's always namespace colon, the name of the view. Three fresh. Oh, that looks a little bit gnarly. Let's let's add an HR in here. Just a horizontal rule. There we go. Add new post. We can add a new post. Cool, cool, cool, cool, cool, cool, cool. And let's add galley belly again. Scroll on down and we see Cuckoo, cuckoo who'll with gullies belly in there. Okay, that's fantastic. This is actually working now. So as far as this lesson goes, this is complete. In the next lesson though, let's make the newest posts show up at the very top. 18. Sorting default posts: All right, let's make the newest posts show up at the very top here. And so this is the oldest post, second oldest, third oldest. You can even see that there named first, second, third. This is the newest image, cuckoo cool. That's the one we added in the last video. Let's reverse this. So let's go into our views here. Let's close all that stuff down and let's just pretend we're starting from scratch feed. We need to go into our views. We need to see our homepage view. And we were basically looping through all of our posts, all of the available posts in our app. And so we're saying Post.all objects dot all, that's going to get all of the objects. And then we can say dot order underscore by, and we can order it by texts or some other form. And so we can order it by its text or ordered by its text descending. Or we could order it by its ID, which is what it's doing by default, or its ID descending. And when I hit refresh up here, we're going to see that this order here flips. It's going to be completely reversed just like that. And it just happened to be the first and last image are the exact same. But this was the newest one. This is the second newest, 1 third newest, 1, fourth newest one and the oldest one. And so all we did there was we said, hey Django, get all of the post objects, get all of them, and then order them by the ID. And we know it has an ID. Every model has an ID by default. And it's even inner migration here, it's called ID order by ID descending with a minus sign. If we said this, this is what it's doing by default and it's going to order 12345678910. If we do descending, this is going to go 10987654321. And that's all we need to do. Next up, let's take a look at how we can add some sort of message to our page when a new image is uploaded. Because when we upload a new image, that just brings us back to this page and we don't actually know if anything has happened. I mean, I guess we could see this is a new image and let's select the image of them, Katlyn. And it shows up at the top so we can see it's working there. But what if you have a lot of users using this? You might not actually be able to see your image first. Someone might have submitted one millisecond after, and it's going to show that 1 first and yours might get lost somewhere. We want to show a message. In the next lesson, we're going to talk about jangle messages. 19. Django messages framework: Okay, let's talk about Django messages. So a message is basically a way to send a little bit of information from one page to another, but it only does it once. So if you're familiar with the idea of sessions, basically it creates a session and once that session is accessed, it deletes it. And so we want to add a little message and little session. And when someone fills out this form and it takes him back to this page, it should say, Hey, you successfully added an image. And this is really, really easy to do in this comes baked in with Django three automatically. So let's open up our editor here, and let's open up Feed views dot py. And first things first, let's go ahead and import. We went to due from go dot contrib, I believe con TrpB import messages. Now if you're learning Django and you're working with an existing Django project, you have to go into your settings and make sure that messages is in there. So if we open up our settings and type in messages, Django contract messages is in R installed apps, it's in our middleware, and it is also in our template contexts processors, which means it can be added to every single template. Doesn't matter what your template is, it can just be automatically automagically added. And so you need to make sure you have those in there. So for now we're gonna do from trip important messages, scroll on down to our form. And when that new object is created, let's add a new message. And so we can add a new message with message dot add message. It takes a request by default. Let's do messages dot success. There's different types. We'll take a look in just a moment at the docks, your post was successful. And let's type in Django messages docks, the messages framework. And so it tells us that we need to have all this stuff set up in our middleware installed apps, contact process, contexts, processors, et cetera, et cetera, storage backgrounds, message levels. Ok, so this is where I got messages, dot success and isn't messages. It's messages, that's what I imported. Messages, dot add message, messages, dot to success. And this is where I got success from. So if it was successful, I'm going to give a success message and this is going to be accessible in our template. If there was an info one we could use messages dot info, debug, warning or error. So we have these five options. I'm gonna go with success because I know that that is going to work well with Bootstrap. Because Bootstrap usually has like, I think it's B G dash success or text dot dash success, something like that. So I know that I think actually all of these might work except for debug. But I want this excess color one down the road. And yeah, if we go down into message tags, that actually tells us. Success is going to give us the tag success, and that's going to be put into our HTML, CSS attribute, our class attribute. And then how do we do this? It says adding a message. So we import our message, we did that already. Messages dot add message. It takes request as its first parameter. A message type is that info success, debug, error, et cetera, and then the message itself. And so here are a few different examples. And when we want to display messages, we can simply copy and paste this. Let's do this. For the time being, this is going to be fine. We can clean this up a little bit later. So let's save this. And let's go into templates based on HTML. It's close that database one. And because this is accessible in every single template, because it's in a context processor, which means it's accessible. And every template we can now say, if there are messages, create a list, an unordered list, and then loop through every message with an LI and says if there's message tags, add the tags in here, that's going to be this access or debug. Or what were the other ones? Info success, warning error and debug. And if, and then the message itself. So it's going to loop through all of them. And we can have multiple messages that's important to know and that's why we're looping through these. Now, let's go ahead and give this a try. And i'm going to show you that this actually has some form of an error. This is going to not work. And I'll just select any image. And it says, Oh, name error, name request is not defined. Now here's the tricky thing, and you're going to want to take note of this because moving forward, this is going to be a life saver. So the first parameter in ad message is request. If we go back to our code here in form valid, we don't have request, we have self and we have formed. So how do we get requests? We're in a Form View here. Let's take a look at where Request exists. Gets when you get the form. So when you're displaying the form, you could access the request, their dispatch HTTP method not allowed options post and setup. And so what we want here is we actually want dispatch. So when this view is being dispatched, when it's being, when it's about to be rendered, what is it going to do? And so let's go ahead and just copy this line. And because it has requests in here, but our method in here form valid does not have requests, but we can do is deaf dispatched self request args, quarks. I literally just copy that from here. Def dispatched self request args, quarks, return super dot dispatch request args and quarks. And so literally at this point in time we're saying, hey, Django, We know you have a dispatch method. I just want to let you know that I want you to use that dispatch method. Honestly, this is pointless, but it becomes less pointless when we do this self.age request is equal to that request object. And because we were in a class, we can use self.age request anywhere else. So now we can type self.age request here because it's being accessed here. Dispatch gets run before form valid does. So it's going to set this for us and then we can access self.age request down the road. Let's go ahead and try this out. Let's just refresh this page. Generate a new message. And I'm going to grab any image. It doesn't really matter. And it says your posted was successful. And that's coming from our base dot HTML. It's in an unordered list. And let's right-click and inspect this. We have a URL with a class of messages, we have an LI with a class of success and in it has your post was successful. We have a UL class of messages. It's going to loop through every message. We have got an LI with message tag, message dot tags. That was success that comes from here. And then the message itself is your post was successful. It says the message in there. And that's all there is to adding messages. So really all we need to do is type messages, dot add message. It takes a request, it has to take that exact request object. It takes some sort of message type or a tag. So we're saying messages, dots, access because this was successful. And then our message itself in our base template because we want this to show up on any page. It doesn't matter where we want it to show up on any page. We're gonna say if there are messages, Cuckoo, cuckoo, cool, loop through those messages and display them. Now watch this when I go back here and it refreshes page, that message goes away, it's very temporary. It only exists once. 20. Adding Bootstrap 5: Okay, let's add a front end theme. And for this we're going to be using Bootstrap five. So we're gonna go to And we are going to use what I'm going to be using five version five beta one. Maybe by the time you're watching this were on a different version. That's cool. And it doesn't really matter. Let's just get started. We need this CSS. Let's go ahead and copy this. This is coming from a content delivery network. We don't need the JavaScript yet. I mean, if you want to, you can add it, but we're simply going to add the CSS and we want to add the CSS on every page. So what we're gonna do is simply paste it in here. And that's going to add it to every page. And that's why we have this base dot HTML. It's going to add it to our detail page, our homepage and our new posts page, and watch this. When I refresh, you're gonna see it looks just a little bit different. Just a little bit different. Hey, it just sort of resets things for us. Now let's go ahead and add a nav bar. And let's, I think it's in components. We're going to find it navbar. And let's find one we like and just copy that. We can always modify the HTML later. Which one do we want? Is there a simple one? And this is a pretty simple one. This is a good one. So we have like a title like image sharer, our homepage, adipocytes. And that's actually all we need. Let's go ahead and copy this. And because we want this on every page, we're gonna throw this inner base dot HTML. Now I'm gonna get rid of a few things here right off the bat. Navbar, I don't want that to be called navbar. I want this to be called image sharer because that's what we created and that's just going to go to the homepage. So it just go straight to slash. It doesn't need a special URL. Because slash is always the homepage of a website. We can go to home. And again, that's just because the way we have the setup is we could use slash or we can use URL, feed index. And again, where that's coming from is if I close views dot py, go to URLs dot py, feed index. That's gonna give us a slash, same as up here. It just happens to be that it's prefixed able. If we wanted the homepage to be something like slash home, that will automatically changed for us. Features. We don't want pricing and we don't want disabled. And instead of features, let's call this add new image. And we need to link this to our Feed post. And where that's coming from is feed post. And that's going to go to this URL here. Let's go ahead and see what this looks like. Maybe this looks terrible. I'm not really sure. Got looks. Okay, I can live with that. I guess it's make us actually a 100%. That's, that's not bad. I can live with that. Now let's go ahead and send her some of our content here. And we're gonna say inner base dot HTML. And let's maybe clean this up first. I'm a stickler for nice clean code. Alright, so I just clean that up. And we want to center all of our content. So let's take a look at containers in Bootstrap five customized content layout containers. And that's exactly what we want. We want to contain or maybe we want a regular size container. And so on. An extra large screen is going to be 1320 pixels wide. On a, that's an extra, extra large. I hadn't realize they did that. Now there's an extra large for it to 1140. Large is nine sixty seven, twenty five forty. Anything below that is a 100%. Let's use a commentator. And let's see what this does. Cool. So that sort of centered it for us. That's good. Let's, let's get rid of this link because we have that already in there. And where did that come from? That came from our home, I believe. Yeah, right there. Let's go ahead and get rid of that. Beautiful. And what we can do is this nav is actually taking up a lot of space. So what we can say here is include, includes slash, navbar index.html. And let's go ahead and copy all of this, not copy but cut. We're gonna go cut. And this is going to look at our templates folder for a subfolder called includes, and then a file called navbar dot HTML. Let's do this. New file includes slash, nope, includes spell it right, slash, nav bar dot HTML paste. And now are based on HTML. Looks nice and clean again, let's just make sure that that's working. That is in fact working beauty, beauty, beauty. What else do we wanna do here? Let's make these cards or something. So what do we want it here? I think that's called a component in Bootstrap. It's a card. Yes, this is exactly what we wanted. We want an image with some text and then a link to view the entire image. Let's go ahead and copy this. And we're gonna throw this inner for-loop on our homepage. Our homepage. Let's go ahead and get rid of that. Let's get rid of that. And let's just make some space to work. And we just want to replace, you know, like the image SRC with this image in here, or this text with postdoc text. So let's actually go ahead and start doing some surgery. Let's go ahead and cut that and put it right into our paragraph, and that's going to be our text. We don't need a card title. If you wanted to, you could extend your model to have a title. So every image could have a title. Go somewhere. Where is this going to go? And that's going to be this link here. And instead of say, go somewhere, Let's make the text say view full image. And then we need to move this thumbnail stuff down and move that. And move that up. And what we need is that image URL. So we grab that image URL. And that alt could be whatever I'll text you want. Where do gonna, we're gonna throw away the image, width and height. And we're gonna give this a class of card image top, which already came with it. And so I guess where I'm giving it, we were already given it. And let's go ahead and save this. And let's get rid of this old stuff up here. Clean this up, make it nice so that people you're working with and don't hate you for writing very sloppy code. Okay? Not bad, not bad. These are all on their own line though. That's not quite what we're looking for. We want all of these to be a column. So let's go ahead and create a new row. And this is just knowledge from old Bootstrap. We create a row, move that div down. And then for every post we want to create a new column. So we could do column SM. When it's small. Let's take up six dot col md for hit Tab m. It automatically does the rest for me. Hey, not bad, not bad. Could be better, but that's not bad. And actually what I should do is I should take a look at the layout in here and the doc's schedule look at the grid. So we do have coalesce m. We just want to make sure that it works the same in Bootstrap five as it doesn't like Bootstrap for Bootstrap three, et cetera, et cetera. Because I might have written the wrong class name. There we go. There's an example column, large T2. That is just proof that what I was looking for was the right thing. So on a medium, let's, let's actually do three. Let's make this a little smaller. There we go. And it needs a little bit of spacing above and below each card. And what happens if I get rid of this? Okay? And it works alright? Under each card, let's do margin, bottom four. But do margin, top and bottom four. There we go. And look at this. We have a nice little image gallery. Let's go ahead and view this image. Okay, so, you know, at the base stuff was applied. That was nice. Let's go ahead and clean this up a little bit. So let's open up our detailed dot HTML. And we don't need a go back link because that's now in the nav bar, it's at home or add new image or the logo. If there was a logo, we don't need that anymore. The text and the image is all we need. And let's go ahead and make this responsive. And I don't know what that actually is in Bootstrap. So let's do a responsive images search. And we want image fluid class. Img fluid. Okay? Okay, not bad. Could be better, I think. Let's see what else we can do. We've got image, thumbnail, Cool. Rounded. Is that what we want? Yeah. Yeah. Yeah, let's do that. Let's make the image rounded. Got really excited about that rounded. And that's just going to give us nice rounded corners. Let's go ahead and maybe throw this into some sort of rho as well. Rho with a call SM, let's say ten, so small and up is going to be a column width of ten. Move that up. And I think it's offset coal no offset SM One, I'm guessing. Did it's entered it. And let's go ahead and add a padding to the top padding, top five. That just bumps it down for us. And let's maybe add padding bottom five. So on the left and right we could do padding X or on the top and bottom we could do padding y p, y five. And it looks like it did nothing but added padding to the bottom down here. Last but not least, we have our posts page. This page looks terrible. Let's go ahead and fix this. Might as well close those. Let's do New Post and that button, let's change that button. Class, btn, btn-success, I'm guessing. Cool. That worked for me. What do we have for forms? Okay, so this gets right into it. And we may not actually have all that control. We don't, because a lot of this has handled for us inside of Django. We don't have access to, not easy access to the label. We actually can't get access to the label and loop through all the form fields and create a form by ourselves. It's a little more advanced. So we're not gonna cover that in Django 101. But what we can do is if we wanted to write some CSS, which we're not going to, but if we wanted to write some CSS, you could say everything inside of your form. With an, say, an input type of text could then be this kind of field. And you can extend it using SAS and things like that. We're not gonna get too into that. Let's just make this page look a little more tidy. So let's add a class here. Class is going to be kohl S M for offset. Quick math here. And 12 minus four is eight divided by two is four. So this is going to center it because there's 12 columns in Bootstrap. And let's add a title to an H two and here, upload an image. And let's add some padding in there as well. Padding top five, margin top and bottom five. And at this point I'm really just experimenting to make this look half decent. And what that button to be bigger to btn dash LG. There we go. Now let's say we want to rearrange text and image. So someone chooses the image first and then rates text. Let's go over to our forums dot pi. And let's simply rearrange this. I just move this up and down. So the first one's going to be image and the second one is going to be taxed safe way for Django to reload. Refresh. And there it is, image first, text later. And let's say we didn't want to call this text because we see it's called text here and image, their image is fine. I think I'll just go ahead and change that label. Label is going to be description. It's still going to be text in the Python code, in the Django code. But the label is going to say description instead. So instead of text right here, it's going to say common load for me. Description, nailed it. Just like that. Last but not least, when we upload an image, we have messages, we need to display a message. And so this often gets missed because it says if messages then do a thing, what we're going to do here is actually we're going to design this outside of the if statement and then wrap the code inside of it. So let's go back to bootstrap and let's do a background color. Background colors. Ooh, let's do a gradient. I like that. And so we can have text success. Who would look at that? We've got lots of omega in here. Bg success because we're using success for message info as well, islets. Where's the gradient? Yeah, this is what we want, BG success and BG gradient. So let's go ahead and create a new bar in here. And let's just throw that in there. Let's make sure the text is centered. And the text is going to be white so we can read it. Dummy text in here. Let's just see what this looks like. Oh, look at that. It's above than f bar. That's two alerting. Let's move that navbar up. Okay, cool. Hi, let's add some padding. Padding, top and bottom is going to be padding y-axis. Let's do four. Okay, I like that, I can live with that. Now we have to move this back into the if statement. And we can do the message tags. It's going to be here. Because we knew that originally it was actually success. We're just going to throw it in there. And then we're going to wrap that in an if statement as well. Like this. And all I'm doing is a little bit of HTML surgery here. And that is a simple if statement. Then we can say else as a default, always fall back to, instead of maybe we didn't give it a message. Let's say it always has to default back to success. So it's saying here, if there are message tags, print those message tags. Otherwise, use success. And if we need to then move this message. And again, dress doing some surgery here, paste. And lastly for and then it down. And there we go. So now this says, if there are messages for message and messages, let's go ahead and style a div, but the message inside of it. And let's add a new image. And let's make sure that this actually works. Testing a Django message. Now your post was successful and due to do, I need to move that backup and that will then move back down. Let's see one more example. Just, just to really drive this home, just to make sure message shows up in their says your post was successful. Now we have one more thing to consider. What if you have a brand new application here and nobody's using it? There are no images. Let's go ahead and delete all these images and we go into posts. Grab all of them. Delete, go. Yep, delete them. Nothing shows up. Doesn't look the greatest, does it? What we can do is on our homepage, because that's where we're looping through all of our posts in our for loop, we can say, if it's empty, right stuff here. And it says write stuff here. Because there's nothing in there. Let's go ahead and add some styling here as well. So we're already in a row, we just need to add a column. So coal SM six dot offset three. Let's make this text center and give it a padding top and bottom of five, margin top and bottom five as well. Lots of spacing. H2, welcome paragraph and a paragraph. Add your first image and a button, a HREF. We're gonna fill that in just a second. Class is equal to btn, btn, LG, BTN success. Because we're going with the green theme here. Upload Image. And we just need that to actually go somewhere. We know how to do this URL, string Feed, post, upload an image that's upload our first image. And let's do golly too, because he is super cute. This is galley. There is a beautiful image. There's gully, We are done our app just like that. 21. Your project: Okay, welcome to your project. We just created an entire Django app from scratch in this course in Django 101, what I would like you to do is if you haven't been following along, I want you to try to recreate this app from scratch. It's going to take a little bit of research. You might have to access the Django docs, you might have to access this beautiful website. It's actually not beautiful, but it's very, very informative. Is CC-BY v dot CIO dot UK. Very, very helpful. You might have to access the bootstrap docs, might have to do little bit of research. It's not going to be super easy, but it's going to be great experience. Or if you want, you don't have to necessarily do it from scratch. You can take all of my source code. You can always download the source code as well from slash Caleb Talia slash Django dash, one-to-one. Make sure you follow the Read Me. I'm going to write a read me in there and then you can just follow along. You can clone it down to your computer and set it up on your own, and then just modify it. I want you to make it look beautiful, make it look and act amazing. So we did all the backend work. You can now just have fun with all the front-end work. In the front-end work is really, really fun. You get to make it really interactive, colorful and beautiful. You can make it look and do different things. But essentially you should be having a project like this on your computer that takes an image, uploads it, and displays a thumbnail, and then we have a detail view in Django. Feel free to modify it to your heart's content. And since you are unskilled share, you have a dedicated project section. It's a little green button that says my project or something like that. You can click that button and you can add screenshots of your code and how it works. Or you can add a video if you wanted to, you could put a video up on YouTube and show me that your project is working and I can give you tons of feedback if you like. 22. Summary: Alright, you did it. You got through all of Django 101. It's been a couple of hours. We made a, a cool image sharing application from scratch. By the way, if you didn't know, this is basically what Instagram was. Instagram was made with Django. Ours just looks a little bit different. Yours could look exactly like Instagram if you wanted it to. But once again, I just wanted to say thank you for taking this course. I'm very proud of you for getting all the way through it. Don't forget, you can always follow me on Twitter at Caleb Italian. Or if you want coating tips and tricks, you can follow coding dot for dot everybody on Instagram. And if you ever get stuck or ever need help whatsoever for anything web development related, come join, learning to code on Facebook. It's a completely free group. All you need is a Facebook account. Thank you again for taking this course and spending this time with me and hopefully I'll see you in the future.