More Styling
Your finished project still looks a bit better than your current project, so let’s spice it up with a bit of Bootstrap. You’re going to center the contents and add some navigation.
00:00 Our finished project still looks a bit better than our current project, so let’s go ahead and spice it up with a bit of Bootstrap.
00:16
I’m going to simply replace what we have in here, for now, with a bunch of Bootstrap code that I copy-pasted. Let’s take a quick look. We’re using a heading for our project.title
, and remember, we’re passing this project
from our view, from the detail_view()
.
00:32
Then, I’m just applying some Bootstrap classes. Here’s an image link to "{% static project.image %}"
, our image URL sitting in here, and as an alternative text, we’re giving a project description.
00:45
Additionally, I’m going to fill 100%
of this column part that Bootstrap creates with this setup. And what we have here is another heading, a smaller heading, {{ project.description }}
, and what does is it built with—the technology.
01:00 Let’s take a look how this looks. When I reload it, this looks already much better. The one thing that’s still different over here is we have the whole thing centered and up there, we also have some nice navigation.
01:15 I will show you how to implement this by just putting the pieces into the right place. This is going to be another bunch of Bootstrap code. Read up on it in the associated text, or just learn some more about Bootstrap if you’re interested in that. For now, we’re just going to make our app look as good as this one does.
01:35
Notice that the page that I’m editing—the template that I’m editing—is going to be base.html
, because I want this header to be appearing on all of the pages that I have inside of my app.
01:47
So, I’m going here above {% block content %}
and I’m pasting a navbar that I just took from the Bootstrap website. We’re also opening up this "container"
class before our block, which is going to add some Bootstrap styling, and I’m going to have to close it afterwards.
02:09 So, what’s happening here is this part
02:15
creates the Bootstrap header, and then this container around whatever content we’re putting in the templates that we’re extending base.html
from, is going to help to apply a certain styling that Bootstrap uses.
02:37
Okay, so look at that! We’re getting a NoReverseMatch
. 'projects:projects'
.
02:45
And that is simply because I copy-pasted that from the finished project, but we actually built it a little differently. So here, I’m linking to 'projects:projects'
, but that’s not how we called it, so we got a NoReverseMatch
. Remember where we go to check?
03:02
We go to check first in urls
, make sure that we have the app_name
—correct—and we have the view name
—'all_projects'
, 'project_detail'
. That’s our home, so that’s where we want to link to.
03:16
And then next, we check inside of the template—in this case, base.html
. We look for the url
tags. Here is one and there it is, see? Okay, the app_name
is correct, but the path()
name
is incorrect. So here, we need the proper path()
name
.
03:34
And we see this happens down here again. So, we’re linking back to the page. And now, we should have dealt with our NoReverseMatch
. Let’s check it out.
03:46 I reload this. It’s working and it finally looks great. We have the navbar up top. We have our details page. Let’s check that when we click Home, we come back to the list view. We can click in here, go to my test project, come back Home, check up the next project.
04:04 Everything is looking nice and very similar to our finished page. Awesome! We’re totally getting there. We did some nice styling here. Congrats. Before we stop the styling for this one, here’s one last thing.
04:21 Take a look at how does this page look like if we check it out on the phone. Now we could not really check it out on the phone yet, but what each modern browser offers are developer tools, if you right-click and then say Inspect Element,
04:38 you can choose to display it either as a normal web page, or if you click up here, as a device. So here, for example, on iPhone X, or you can choose a different phone, as well.
04:52 Our page looks pretty crappy on the phone, right? Do you see that? Like, it’s very small. Imagine seeing a page like that on your phone. You would probably not impress anyone with your portfolio if it looks like this.
05:03
So, there’s actually a very simple thing we can do to solve this problem because we’re using Bootstrap, which is designed for being mobile-responsive. The only thing we need to do is add this one line of HTML code into our base.html
so that it applies to all of the pages. You can simply Google this one if you don’t know it. It’s the meta
"viewport"
, and then it allows us to make the page mobile-responsive by declaring that the content is going to look for what’s the device screen-width, and then adapt to that one. I’ll put it into the code now, and then we can see how much better our page looks on the phone.
05:51 I put this viewport line in here. If we reload the page now, you can see that this looks much better. Now, the cards adapt to the device width, and we can click here, Read More.
06:05 Also, our single page looks quite decent. So, that’s nice. With this said and done, I think we’re fine with leaving the design as it is right now. You can always dive deeper into this front end development if you want to make it look better, check out Bootstrap, but I think we’ve got a pretty decent page that looks good both on the phone as well as just normally on the browser.
06:31 Okay, great! So, what I want to show you in the next video is moving a bit away from styling, but we want to be able to add more of those projects and we want to make this in an easier way than always having to go into the Django shell.
Martin Breuss RP Team on Oct. 23, 2019
The Home
and other nav buttons are still present, Bootstrap’s responsive nav-bar simply nests them in a drop-down menu to optimize for space.
When you click on the hamburger menu on the top right of the page (when viewed on a phone) you should see the other nav links there.
reblark on Nov. 14, 2019
Once again, I believe I have done everything right. I have spent much time debugging and found many errors that I have corrected. The additional styling does not appear even though the page does. I am just showing you the source code from the page, (show source code in Safari) to show you that the class “col-md-8” doesn’t make it. It’s like the new code in detail.html just doesn’t make on the path to the page. If you think there is something specific I should look for, I would appreciate knowing it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Portfolio</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Projects</h1>
<div class="row">
<div class="col-md-4">
<div class="card mb-2">
<img class="card-img-top" src="/static/projects/img/720720.jpg">
<div class="card-body">
<h5 class="card-title">Good, good</h5>
<p class="card-text">this is with good image</p>
<p class="card-text">Django</p>
<a href="/projects/4"
class="btn btn-primary">
Give me More
</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card mb-2">
<img class="card-img-top" src="/static/projects/img/Nancy2.jpg">
<div class="card-body">
<h5 class="card-title">More good</h5>
<p class="card-text">Nancy at her best</p>
<p class="card-text">Django</p>
<a href="/projects/5"
class="btn btn-primary">
Give me More
</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
reblark on Nov. 14, 2019
The video at 1:23 shows three tabs at the top: Portfolio Home Blog
At 3:51, after adding the Bootstrap code, the tabs are: Portfolio Home
Somehow, blog didn’t make it.
reblark on Nov. 15, 2019
However, when you check the page and blog is missing, when you click of the “more” button, blog appears again. When you go back, it disappears. Clearly some inconsistency here somewhere.
reblark on Nov. 15, 2019
How do I copy the Bootstrap code to put in the base.html file?
reblark on Nov. 15, 2019
The problem that I have struggled with is caused by not having access to the bootstrap code. How can anyone trying to follow along with your app develp that app without the code? Did you supply it somewhere that I missed? The frame in your video is to narrow to show the whole code, otherwise I would just freeze the frame and hand copy the code. Am I legitimately frustrated or did I make a big miss? I would very much like to complete this.
Dan Bader RP Team on Nov. 15, 2019
@reblark: The associated written tutorial (under Supporting Materials) has a downloadable sample project. I’ve also added direct links throughout the course now (for example in the first lesson and in the last one). Hope that helps you out! :)
Martin Breuss RP Team on Nov. 16, 2019
Hei @reblark–yes, the finished project I am showing is the one from the associated written tutorial, which has an additional Blog app built out that I’m pointing to in the final section.
reblark on Nov. 17, 2019
Dan and Martin
Thanks to both of you for responding. With all due respect, I feel that the ending of Martin’s tutorial is a bit messy. As you know, all along, I tried diligently to follow and replicate the app. The ending just isn’t quite right with two different pages—one with “”, one with not—and providing the code that Martin used in the last styling video should have been easy. Just referring to the written tutorial, which does not discuss that code in detail and having an unfamiliar reference to the Bootstrap code in the beginning is, well, to me, it could have been better, more responsible. I am really trying my best and when you present the styling video and show me the cool work that can be done then tell me to go study Bootstrap separately because you are not tidying up at the end, hurts. The blog app, of course, is an entirely different and exciting issue, but finishing up this app cleanly and completely is important to me. I would hope that somehow I could get a copy of the code that Martin put in the base.html file in that video. That should be easy, I think.
I am grateful for this course and starting others, like Migrations, but I really would like to finish this one neatly and correctly.
Cheers. Ralph
reblark on Nov. 17, 2019
By the way, I wondered during the course what language spells “hi” as “hei?” Must be your native language Martin.”
reblark on Nov. 17, 2019
Oh, by the way, I think I found what I was looking for in terms of finishing the site. I found the stuff about the Boostrap code for the blog. Exciting.
marcinmukosiej on Dec. 16, 2019
reblark is right. There are not that many lines of code in “More Styling” video. Copy-paste was a ‘shock’ to me and now back @Bootstrap there is completely different code for that bright-gray navbar :)
At least Martin is quickly showing full code in a video, so I can pause,write it down and inspect.
rhysflook on Dec. 20, 2019
Anyone else having similar problems to reblark can find the html code in the sample project zip file, that is where I found it.
rolandgarceau on Jan. 24, 2020
Is there a tutorial on implementing styling without having to use CORS or bootstrapping?
Martin Breuss RP Team on Jan. 24, 2020
For learning to implement all the styling by yourself without using a framework (whether it’s served through a CDN or downloaded and directly included in your project), you’d need to look for a tutorial on writing CSS.
Since Real Python is a site focused on Python, we don’t have tutorials specifically on CSS. I’ve personally found CSS Tricks to be a great resource, however, it’s more a compendium of CSS topics than a full-fledged intro tutorial.
Martin Breuss RP Team on Jan. 24, 2020
@marcinmukosiej what do you mean you are missing? You can download the project code at the top under Supporting Materials.
Let me know if there’s something else that you’re missing.
rolandgarceau on Jan. 27, 2020
I’m looking for a Django and Python specific tutorial for styling. I have experience with Babel, Webpack, and React apps- and how CSS can be used for a Reaact Portfolio. I would like to explore how to create a similar structure for this django portfolio without having to rely on outside websites to be operational in order for my site to look good.
The path I am heading is to have django framework housed on AWS and to put my django portfolio into production in a S3 bucket- again without using AWS’s CDN, but manually doing so as to be able to learn what it actually means to create all the parts of things like beanstalk would do or and other currently used highly abstracted automation from AWS. In the solutions architect tract from acloud.guru in 2018 the CDN tooling was very abstract, and now I would like a much deeper understanding of how to have ownership of such production grade endeavors than things like a simple SQLite3 DB and a loopback address on my own machine.
If there is a tutorial on production grade site building which includes PostgreSQL or a no SQL solution, including a means to remove the dependencies associated with using a bootstrap, that is what I will be looking for after creating a few blogs for some friends of mine. I do realize technology moves fast, and I just wanted to see if anyone at Real Python has already been put top this task in 2020, instead of me having to spend precious time digging through other tutorial sites, which often yield in paid services losing me as their customer.
Ricky White RP Team on Jan. 27, 2020
Hi @rolandgarceau. You could look into Django REST framework instead? That way you could separate your back-end as an API and use your React skills to use a react front-end for your apps. Using Javascript based PWAs is becoming quite common, and Django REST framework is a great way to supply a back-end for such an app.
monika on April 24, 2020
To write only “Paste via cmd+V” is not a good way for the lines from Bootstrap. The code is not accessible within the provided .zip directory. Why could you not provide this here?
Ricky White RP Team on April 26, 2020
Hi @Monika.
You can get the code for Bootstrap nav from their official docs page, here: getbootstrap.com/docs/4.4/components/navbar/
monika on April 27, 2020
Hi Rick. Thanks! Good support. I might have another question… I’m planning something like a Dashboard. Main topic is to provide several display types/tabledata in one view. How far I did understand django structure, I have to make several def functions within in one class based view in views.py responding different table data requests and if possible simple text without relationship to a database. Can I find an appropriate lesson in RealPython Tutorial or elsewhere? Perhaps you find the time to tell me another helpful link?
Martin Breuss RP Team on April 27, 2020
Hi @Monika. In Django, class-based views and function-based views (the ones used in this tutorial) are different things. You wouldn’t nest a function-based view, the ones you make with def
, inside of a class-based view.
Generally, you can make multiple database queries in one function in views.py
and pass all the results to a template via the context
dictionary. This allows you to render data from multiple different tables in one view, that you could design as a dashboard.
Check out this tutorial link which might provide you with the info you need.
BlackJesus on May 6, 2020
For anyone facing what @reblark and others experienced, here’s the bootstrap code.
------------------------------BootstrapCodeBegin------------------------------
<nav class=”navbar navbar-expand-lg navbar-light bg-light”> <div class=”container”> <a class=”navbar-brand” href=”{% url ‘projects:all_projects’ %}”>Portfolio</a> <button class=”navbar-toggler” type=”button” data-toggle=”collapse” data-target=”#navbarSupportedContent” aria-controls=”navbarSupportedContent” aria-expanded=”false” aria-label=”Toggle navigation”> <span class=”navbar-toggler-icon”></span> </button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="{% url 'projects:all_projects' %}">Home</a>
</li>
</ul>
</div>
</div>
</nav>
close it properly by adding </div> after {% endblock %}--------------------------------BootstrapEnd--------------------------------
BlackJesus on May 6, 2020
I messed it up, here it is.
------------------------------BootstrapCodeBegin------------------------------
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="{% url 'projects:all_projects' %}">Portfolio</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="{% url 'projects:all_projects' %}">Home</a>
</li>
</ul>
</div>
</div>
</nav>
close it properly by adding </div> after {% endblock %}
--------------------------------BootstrapEnd--------------------------------
karakus on June 14, 2020
Hei Martin,
Thank you for this well paced and informative course. What I particularly valued was the ‘error centric why’ that gave context to the ‘what’. Now I find I groan less when I get an error :)
One thing I did note is that you only <link> to the Bootstrap css stylesheet in the Tutorial, and the Sample code. Whereas, I couldn’t get my Hamburger toggle to work until I added into base.html a jquery script and a Bootstrap javascript, as specified in the Bootstrap4 documentation. Is that what you’d expect me to need to do?
Martin Breuss RP Team on June 15, 2020
Hi @karakus, glad you’re liking the error-centric approach :)
Nice work on figuring out the Bootstrap hamburger menu! 🙌
Collapsible Hamburger Menu
You are right, Bootstrap’s default function of expanding the hamburger menu when it is collapsed relies on JavaScript code that you can include in your page by adding the following two lines to the <head>
of your base.html
:
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
Responsive Expanded Menu
If you want to keep your code as lean as possible and don’t add any JavaScript to it, and still keep the menu functional also on mobile, another option is to change the navbar-toggle
and/or navbar-collapse
classes to navbar-expand
.
This will simply avoid collapsing the menu items into a hamburger menu and always display them at the top of your mobile page, just like it does on the web browser.
karakus on June 16, 2020
Thanks Martin - I’ll try that.
I have one other question that I’ve not found a definitive answer for … yet, which I’d value your input on if you have the bandwidth.
I’m working on adding the Blog app to the Portfolio project and I’m unsure of whether I should place base.html in a portfolio/templates folder and change the individual app templates to reference that, thereby adhering to the DRY principle across the portfolio. Or whether, for app portability reasons, I should keep a base.html in each app templates folder. I’m also wondering whether the django template language would enable me to put a conditional statement in that looks in the top level (portfolio/templates) folder for a base.html first and only use the app specific one if the portfolio one doesn’t exist.
PS: I currently have base.html at the portfolio level and actually used the friendly errors to figure out what I needed change in various places to ensure my app templates found it!
Martin Breuss RP Team on June 18, 2020
Hi @karakus! That’s an interesting question and might come down to personal preference, although let’s see what Django suggests:
One common way of using inheritance is the following three-level approach:
- Create a
base.html
template that holds the main look-and-feel of your site.- Create a
base_SECTIONNAME.html
template for each “section” of your site. For example,base_news.html
,base_sports.html
. These templates all extendbase.html
and include section-specific styles/design.- Create individual templates for each type of page, such as a news article or blog entry. These templates extend the appropriate section template.
While this doesn’t explicitly address your question about multiple apps, I could see it used like that as well. E.g. you’d use a project-wide base.html
template, and then app-specific base_APPNAME.html
templates etc.
Personally, I would make this choice on a per-project basis, since both approaches make sense to me. If it’s a project where the apps are tied together rather firmly and it’s unlikely that I would segment one of them out to use it elsewhere, then I would opt for the general base.html
template, especially if unified styling and structure is something I’m going for. Otherwise, having everything neatly packaged inside of its app feels the most comfortable to me. :)
Tl;dr: I’m not sure there is a definite answer to your question. There are some good practices you can follow, such as the approach of double-inheritance that the Django docs suggest, and it’s a good idea to consider the trade-offs of either approach on a per-project basis.
Other Approaches
There are also ways to make the inheritance conditional that I have never used myself, but you could play around with it. Here are two links on StackOverflow:
- stackoverflow.com/questions/5380984/any-way-to-make-extends-conditional-django
- stackoverflow.com/questions/2575282/django-conditional-template-inheritance
I like sticking with the other approach better, though, since it feels to me this could potentially get a little messy ¯\_(ツ)_/¯
karakus on June 18, 2020
Thanks for the info Martin - it all helps!
charneuk on Aug. 14, 2020
i’m still getting this error message
NoReverseMatch at /projects/1 ‘projects’ is not a registered namespace
Martin Breuss RP Team on Aug. 15, 2020
Hi @charneuk. For the NoReverseMatch
to go away, there are a couple of things you can check, see if you can find the bug by following the suggestions in NoReverseMatch
Debugging.
Let me know what you tried and what worked - or if it didn’t work so we can dig deeper.
KatMac on July 23, 2021
HI Martin
I have created a new file called “custom.css” and placed it in the same folder as base.html, all_projects.html etc. and added this code to the base.html head tag…
<link rel="stylesheet" href="http://127.0.0.1:8000/projects/custom.css">
It isn’t finding this file. Is there something I am missing here?
Martin Breuss RP Team on July 26, 2021
Hi @KatMac, if you want to add your own CSS file to customize your app’s look and feel, you’ll have to handle that CSS file as a static file.
In short, just like you want to remove hardcoded URLs from templates, you’ll also want to handle static files without hardcoding your URLs:
# your-template.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'projects/custom.css' %}">
Hope that helps! :)
Eli on Oct. 30, 2021
Hey Martin, first of all thank you for being responsive here to help guide us, and also thanks to the community for helping us to find the same navbar from bootstrap that you are using. Honestly I was unsure which navbar to grab. MY question is about the meta structure. I noticed that I can either add a second meta tag for the device view or i could add it to the existing tag. Is there a best practice or is that personal preference?
Martin Breuss RP Team on Nov. 2, 2021
Hi @Eli, I’d suggest to add a second <meta>
tag. This keeps the information logically separate:
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
The first meta tag is about character encoding, the second one about your site’s viewport. At least to me this approach makes it less effort to maintain, because I can find the information I need more quickly.
samjeezy on July 24, 2023
I keep getting this error. Any nudge in the right direction would be appreciated.
Exception Type: NoReverseMatch Exception Value: Reverse for ‘projects’ not found. ‘projects’ is not a valid view function or pattern name.
Martin Breuss RP Team on Aug. 2, 2023
samjeezy did you check out the lesson on debugging this error? It could be a couple of reasons you’re getting the error, that lesson gives you hints and approaches on how to tackle it: realpython.com/lessons/noreversematch-debugging/
Become a Member to join the conversation.
Gascowin on Oct. 21, 2019
I observed that when you previewed the app in the Iphone view that the ‘Home’ nav button failed to show. I added some other buttons like a dropdown link in my own version of the app that also would not show unless I previewed the app on an iPad Pro. I could not seem to fix this. Would you happen to know of a way around this?