Content
Theming and Styling your Django Site
settings.py
Open up homepage/homepage/settings.py and replace
MARKDOWN_EXTENSIONS = [
'markdown.extensions.tables',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
'markdown.extensions.attr_list',
'markdown.extensions.footnotes',
'markdown.extensions.wikilinks',
'pymdownx.superfences',
]
with
MARKDOWN_EXTENSIONS = [
'markdown.extensions.tables',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
'markdown.extensions.attr_list',
'markdown.extensions.footnotes',
'markdown.extensions.wikilinks',
'pymdownx.superfences',
'pymdownx.tasklist',
'markdown_mermaid',
'pymdownx.caret',
'pymdownx.mark',
'pymdownx.tilde',
]
This allows you to render more markdown content than before.
- tasklist allows you to display checkboxes
- whether checked or
- unchecked
- caret allows you to render superscript and underlines
- mark allows you to highlight text
- the tilde package allows you to
strikeouttext - markdown_mermaid allows you to render and display "mermaid" drawings:
base_generic.html
Replace the html in homepage/blog/templates/base_generic.html with the following:
<!doctype html>
<html lang="en" data-bs-theme="auto">
{% load static %}
<head>
{% block title %}
<title>DanAukes.com</title>
{% endblock %}
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<meta name="author" content="Daniel M. Aukes" />
<link rel="icon" href="{% static 'favicon.png'%}" type="image/png" />
{% include 'common/libraries_header.html' %}
{% block custom_libraries %}{% endblock %}
</head>
<body>
{% include 'common/header.html' %}
<main class="container">
{% block content %}{% endblock %}
</main>
{% block footer %}
{% include 'common/footer.html' %}
{% endblock %}
{% include 'common/libraries_footer.html'%}
</body>
</html>
Summary of changes:
- we added some
metatags with more detail about the page, including the site description, author, encoding, and viewport - we added a "favicon", a link to a static image that can be used in browsers in tabs and bookmarks
- below the title block we are including come common libraries that need to be loaded in the header using both the include tag to include some boilerplate libraries
- we also added a custom library block in case we need to pre-load any special libraries for specific pages.
One thing to note is that we've kept most of the stylistic content out of base_generic.HTML. This allows us to customize each page in our own way.
libraries_header.html
The library's header.html file includes links to the content that provides styling and extra functionality not provided by Django, including cascading style sheets (css). The most important one is probably the bootstrap framework. This framework allows us to use reusable components to create pages that look good with minimal styling.
Other notable libraries include Google Fonts, the G-lightbox CSS sheet for styling and creating image galleries on pages, and my custom pymdownx.css and main.css files
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<meta name="theme-color" content="#712cf9" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cabin:ital,wght@0,400..700;1,400..700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
{% load static %}
<link rel="stylesheet" href="{% static 'css/pymdownx.css' %}" />
<link rel="stylesheet" href="{% static 'css/main.css' %}" />
`libraries_footer.html
Similar to libraries header.html, libraries footer.html is provided to allow loading JavaScript libraries and other content that doesn't need to be loaded until the rest of the page is loaded. Because it is inserted close to the bottom of the webpage, these files will not be accessed until later in the loading process.
Some notable libraries that we've included are the popper.js file, the bootstrap.js file, the glightbox.js file, and the mathjax.js file. We also have included a one-line JavaScript script that loads the glight box class.
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js" integrity="sha384-G/EV+4j2dNv+tEPo3++6LCgdCROaejBqfUeNjuKAiuXbjrxilcCdDz6ZAVfHWe1Y" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/mcstudios/glightbox/dist/js/glightbox.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/masonry-layout@4.2.2/dist/masonry.pkgd.min.js" integrity="sha384-GNFwBvfVxBkLMJpYMOABq3c+d3KnQxudP/mGPkzpZSTYykLBNsZEnG2D9G/X/+7D" crossorigin="anonymous" async></script>
<script>
MathJax = {
tex: {
inlineMath: {'[+]': [['$', '$']]}
},
svg: {
fontCache: 'global'
}
};
</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11.14.0/dist/mermaid.min.js"></script>
{% load static %}
<script src="{% static 'js/color-modes.js' %}"></script>
<script type="text/javascript">
const lightbox = GLightbox({ });
</script>
download the color-modes.js file from bootstrap's github and save into homepage/blog/static/js/
post_detail.html
Our rendered post.html file has also been upgraded quite a bit. We now encapsulate the list of parent folders in a separate row to better isolate them.
{% extends "base_generic.html" %}
{% block title %}
{% if post.get_title %}
<title>{{post.get_title}} | DanAukes.com</title>
{% else %}
<title>DanAukes.com</title>
{% endif %}
{% endblock %}
{% block content %}
<div class="row">
<div class="">
{% if parents %}<p>{%for item in parents%}/<a href="{{item.1}}">{{ item.0 }}</a>{%endfor%}</p>{% endif %}
</div>
</div>
<div class="row g-5">
<div class="col-md-8">
{% if post.get_image %}
<img class="headline" src="{{ post.get_image }}">
{%endif%}
<article class="blog-post">
{% if post.get_title %}
<h1 class="display-5 link-body-emphasis mb-1">
{{post.get_title}}
</h1>
{%endif%}
<p class="blog-post-meta">
{% if post.date %} {{post.date|date:"l, F d, Y" }}{% endif %}
{% if post.author.first_name or post.author.last_name %} by {{post.author.first_name }} {{post.author.last_name }}{% elif post.author %} by {{post.author}}{% endif %}
</p>
{% if post.get_summary %}
<p class="blog-post-caption">{{ post.get_summary}}</p>
{% endif %}
<hr>
{% load static %}
<div class="markdown">
{% with rendered_markdown=post.render_full_markdown %}
{{ rendered_markdown.html | safe}}
{%endwith%}
</div>
</article>
</div>
<div class="col-md-4">
<div class="position-sticky" style="top: 2rem">
{% if post.tags.all|length %}
<div class="p-4 mb-3 bg-body-tertiary rounded">
<h4>Tags</h4>
{% for tag in post.tags.all %}
<a href="/posts/tag/{{ tag.name }}"><span class="badge bg-primary">{{ tag.name }}</span></a>{% endfor %}
</div>
{% endif %}
{% block sidebar %}
{% include 'common/sidebar.html' %}
{% endblock %}
</div>
</div>
</div>
{% endblock %}
{% block footer %}
{% include 'common/footer.html' %}
{% endblock %}
The rendered post has added quite a bit of meta information about each post in its display. We now include the post title, the date that has been formatted. We include the author's full name if it is available or the author's username if not, and we include the summary.
We have also wrapped the Markdown content in a specially classed Markdown div. This will allow us to stylize this rendered HTML separately from all of the packaging surrounding it. This allows us to reduce the amount of special filters that we might need to use when rendering our markdown to HTML.
post_list.html
We now need to update the post-list.html file to accommodate our new bootstrap theme. This file also extends off of base-generic.
{% extends "base_generic.html" %}
{% block content %}
{%if parents %}
{%for item in parents%}/<a href="{{item.1}}">{{ item.0 }}</a>{%endfor%}
{%endif%}
<h1>{% if current_folder%}Posts in {{current_folder}}{%else%} Posts {%endif%}</h1>
{% if children %}
<h2>Sub-Folders</h2>
{%for child in children%}
<a class="btn btn-primary me-1 mb-2" href="/{{child.name}}" role="button">{{child.name}}</a>
{%endfor%}
{%endif%}
{% if post_list %}
{% if children %}
<h2>Posts</h2>
{%endif%}
<div class="row" data-masonry='{"percentPosition": true }'>
{% for post in post_list %}
<div class="col-md-6">
{% include 'common/mini_post.html' %}
</div>
{% endfor %}
</div>
{% else %}
<p>There are no posts {% if current_folder%} in {{current_folder}}. {%else%}in the blog.{%endif%}</p>
{% endif %}
{% endblock %}
Even though the general structure of the file is mostly unchanged, we have added div elements with custom bootstrap classes. For example, we now have a custom formatted mini post template that we use to display each post. These are included from another file but are contained within a row, which means that if each mini post is a div type of class column, then they can be stacked quite easily.
Similarly, after our posts, the list of child folders is now stylized to use bootstrap's button styles instead of plain text to represent each subfolder. The general function and structure hasn't changed, but the look and feel has.
The other thing you'll note is that we are taking advantage of more context variables. We can change the heading based on whether we are looking at a folders, posts, or all posts now.
header.html
header.html includes the navbar and is inserted into base generic just above the main content block. Most of the functionality of the navbar comes from bootstraps, documentation, and templates.
There are two sets of lists inside the menu, however, that are of note. The first set of elements includes the work blog and notebook and these link to specific top level folders in our markdown posts.
Nested inside that list is the collapsed nav bar that includes other elements that don't fit on the main menu locks, inc, including the recipes and travel sections.
Note that it is probably bad form and bad practice to have a static fixed link to a dynamic page that may or may not exist. Future improvements to this project would allow me to dynamically configure the menus based on what folders are present.
Also note that we don't use hard-coded links here, but instead use the URL tag to form our own URLs dynamically. This is the best practice and we do it whenever we can, although there are some parts of the project that use static links. I will try to point these out when I can.
One final note is that the nav element uses the fixed-top to maintain persistence on the top of each webpage. This requires your main element to include some extra padding on the top. Later in this chapter you'll see in main.css that we included 75 pixels of padding on the top and bottom.
<nav class="navbar navbar-expand-lg bg-body-tertiary fixed-top">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'index' %}">Dan Aukes</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 me-auto mb-2 mb-lg-0">
<li class="nav-item"><a class="nav-link" href="{% url 'find_top_folder' top_dir='work-blog' %}">Work Blog</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'find_top_folder' top_dir='notebook' %}">Notebook</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">More...</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'folders' %}">Folders</a></li>
<li><a class="dropdown-item" href="{% url 'posts' %}">All Posts</a></li>
<li><a class="dropdown-item" href="{% url 'find_top_folder' top_dir='recipes' %}">Recipes</a></li>
<li><a class="dropdown-item" href="{% url 'find_top_folder' top_dir='travel' %}">Travel</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
footer.html
The footer template includes the footer elements along with the copyright and a link back to the top of the page. Just like the nav bar at the top, this is attached to the bottom using the fixed bottom class provided by bootstrap. This requires extra padding in the body element, which I have included in main.css, as mentioned above.
<footer class="footer fixed-bottom text-center text-body-secondary bg-body-tertiary">
<p class="mt-3 mb-0">Copyright © 2026 Dan Aukes.</p>
<p class="my-0"><a href="#">Back to top</a></p>
</footer>
mini_post.html
MiniPost.html provides a small container for showing a preview of a post, it includes some of the author metadata underneath the title as well as the summary if it is available. In future iterations of this template I will include the post's image if it is available as well as its tags, but this
{% load static %}
<div class="card mb-3">
<div class="{% if rowclass %}{{rowclass}}{%else%}row{%endif%} g-0">
{% if post.get_image %}
<div class="{% if imgcolclass %}{{imgcolclass}}{%else%}col-md-4{%endif%} rounded" style="background-position: center; background-image: url('{% if post.get_image %}{{ post.get_image }}{% else %}{% static 'bg-secondary.png' %}{%endif%}'); background-repeat: no-repeat; background-size: cover;{% if imgminheight %}min-height:{{imgminheight}};{%else%}{% if post.get_image %}min-height:120px;{%else%}min-height:30px;{%endif%}{%endif%}">
</div>
<div class="{% if txtcolclass %}{{txtcolclass}}{%else%}col-md-8{%endif%}">
{%else%}
<div class="{% if txtcolclass %}{{txtcolclass}}{%else%}col-md-12{%endif%}">
{%endif%}
<div class="card-body d-flex flex-column h-100">
<h5 class="card-title"><a class="text-underline-hover" href="{{ post.get_markdown_url }}" >{{ post.get_title }}</a></h5>
<p class="card-text"><small class="text-muted">
{% if post.date %} {{post.date|date:"l, F d, Y" }}{% endif %}
{% if post.author.first_name or post.author.last_name %} by {{post.author.first_name }} {{post.author.last_name }}{% elif post.author %} by {{post.author}}{% endif %}
</small></p>
<div class="card-text mini-post">{{ post.summary_or_short_generated_preview | safe}}</div>
<a href="{{ post.get_markdown_url }}" class="btn btn-secondary mt-auto mx-auto px-4">Read More</a>
</div>
</div>
</div>
</div>
sidebar.html
Sidebar.html is simply a container that holds two other containers. We will add to this as we grow our website. It allows for easy reorganization if you want to put things in a different order.
<div class="position-sticky" style="top: 2rem">
{% include 'common/about-blurb.html' %}
{% include 'common/elsewhere.html' %}
</div>
about-blurb.html
One new element of our sidebar is the about section. This small template file can be included into any set sidebar and reused in a relatively modular way.
{% load static %}
<div class="p-4 mb-3 bg-body-tertiary rounded">
<img class="img-fluid" src="{% static 'images/headshot_shrunk.jpg' %}">
<h4>About</h4>
<p class="mb-0">I am an engineer and educator, having spent ten years as a professor. My goal is to help you build your knowledge of design and technology, get your hardware working, and propel your startup or small business. Get in touch!</p>
<p><a href="{% url 'find_top_folder' top_dir='about' %}">Read More...</a></p>
</div>
headshot
download https://files.danaukes.com/images/headshot_shrunk.jpg and save the file in the homepage/blog/static/images folder.
You can save your own headshot here instead!
elsewhere.html
The elsewhere.html file includes a list of external links that can be accessed in the sidebar. It is formatted as a ordered list, but uses the unstyled class in Bootstrap to eliminate the numbering.
<div class="p-4">
<h4>Elsewhere</h4>
<ol class="list-unstyled">
<li><a href="https://github.com/danaukes">GitHub - danaukes</a></li>
<li><a href="https://github.com/danb0b">GitHub - danb0b</a></li>
<li><a href="https://www.linkedin.com/in/dan-aukes-502995212/">LinkedIn</a></li>
</ol>
</div>
index.html
Just as before, we are extending the index.html page from the base_generic.html file. We have added Bootstrap classes to new div elements to provide more visual structure to the page.
Even though it is currently blank, the index.html page shows the future layout of the front page. We will add content to this later, but for now you can see that we have added bootstrap classes to the div elements.
Some of the notable bootstrap classes that we are using include rows and columns. Columns usually go inside a row. rows have a width of 12 units wide, and columns can typically divvy up those 12 units in a number of ways. In our case, we have two main columns, one which is eight units wide and the other that is four units wide to act as the sidebar.
After the content block we have the footer block which simply includes the boiler plate common footer for now. The cool thing about using blocks is that you can combine includes and blocks together quite easily to enable you to reuse your commonly used elements while adding to that if you wish. In this case, we keep our footer block just using the standard.
article.html
We can also add an article template for allowing us to stack multiple articles into the same web page. We won't use this now, but you can see that it is very similar to post-rendered.html, but doesn't include any of the outside packaging simply with the article contents.
{% extends "base_generic.html" %}
{% block content %}
<div class="p-4 p-md-5 mb-4 rounded text-body-emphasis bg-body-secondary">
</div>
<div class="row mb-2">
</div>
<div class="row g-5">
<div class="col-md-8">
<h3 class="pb-4 mb-4 border-bottom">From the Firehose</h3>
</div>
<div class="col-md-4">
<div class="position-sticky" style="top: 2rem">
{% include 'common/sidebar.html' %}
</div>
</div>
</div>
{% endblock %}
{% block footer %}
{% include 'common/footer.html' %}
{% endblock %}
favicon.png
download https://files.danaukes.com/favicon.png and save the file in homepage/blog/static. You can/should make your own file eventually, but for now, you can put this file there.
To make your own image, any png sized exactly 50x50 pixels will work well. Remember to keep the
favicon.pngname to keep the site functioning. A good tool to design in is Inkscape.
bg-secondary.png
download https://files.danaukes.com/bg-secondary.png and save the file in homepage/blog/static. This is a placeholder image used in case an image is not supplied with the post.
main.css
Finally, we have our main.css style sheet. This is linked to inside the header library.html file.
Overall, this CSS cascading style sheet is responsible for setting the font and font sizing for main body text as well as heading text.
Many of these elements have been created just to permit easier spacing. Additionally, this is where we set the font and background color for our pre elements
Finally, closer to the bottom, we have custom sizing and coloring for images, videos, and table elements inside our Markdown content.
body {
padding-top: 60px;
padding-bottom: 70px;
font-family: "Roboto", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
line-height: 24px;
font-variation-settings: "width" 100;
}
/* :root {
--navbar-height: 50px;
} */
:target {
scroll-margin-top: 80px;
scroll-margin-bottom: 80px;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Cabin", sans-serif;
}
.flex-auto {
flex: 0 0 auto;
}
.blog-post {
margin-bottom: 2rem;
}
.blog-post-meta {
color: #727272;
}
.blog-post-caption{
font-style: italic;
border-bottom: 1px;
}
pre {
font-family: "Roboto Mono", monospace;
padding: 1rem;
margin: 1px;
background-color: rgba(var(--bs-tertiary-bg-rgb)) !important;
border-radius: var(--bs-border-radius) !important;
}
blockquote {
padding: 1rem;
margin: 1px;
background-color: rgba(var(--bs-secondary-bg-rgb)) !important;
border-radius: var(--bs-border-radius) !important;
}
blockquote p{
margin: 1px;
padding: 1px;
}
.navbar-brand {
/* color: #dd0202 !important; */
}
.navbar-nav .nav-link {
/* color: #636e3d !important; */
}
.headline {
max-width: 100%;
height: auto;
}
.markdown img{
max-width: 32%;
max-height: 400px;
height: auto;
}
.markdown video{
max-width: 100%;
max-height: 400px;
height: auto;
}
.mini-post img{
max-width: 100%;
max-height: 120px;
height: auto;
width: auto;}
.mini-post video{
max-width: 100%;
max-height: 120px;
height: auto;
width: auto;
}
.mini-post iframe{
max-width: 100%;
max-height: 120px;
height: auto;
width: auto;
}
.markdown td,.markdown th{
border-style: solid;
border-width: 1px;
border-color: rgba(var(--bs-secondary-rgb)) !important;
padding: .5rem;
margin: .5rem;
border-radius: var(--bs-border-radius) !important;
}
.markdown table {
margin: 1px;
background-color: rgba(var(--bs-secondary-bg-rgb)) !important;
border-radius: var(--bs-border-radius) !important;
}
.text-underline-hover {
text-decoration: none;
color:var(--bs-dark-text-emphasis);
}
.text-underline-hover:hover {
text-decoration: underline;
color:var(--bs-primary);
}
pygmentize.css
The pygmentize command can be used to generate a CSS file that is compatible with the Python-markdown extension, specifically how it formats language specific fenced code blocks. This requires the Superfences extension, which is more compatible with my existing Markdown files than the built-in Python markdown inline fences extension.
pygmentize -S tango -f html > blog/static/css/pymdownx.css
or you can use the same one I used:
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.hll { background-color: #ffffcc }
.c { color: #8F5902; font-style: italic } /* Comment */
.err { color: #A40000; border: 1px solid #EF2929 } /* Error */
.g { color: #000 } /* Generic */
.k { color: #204A87; font-weight: bold } /* Keyword */
.l { color: #000 } /* Literal */
.n { color: #000 } /* Name */
.o { color: #CE5C00; font-weight: bold } /* Operator */
.x { color: #000 } /* Other */
.p { color: #000; font-weight: bold } /* Punctuation */
.ch { color: #8F5902; font-style: italic } /* Comment.Hashbang */
.cm { color: #8F5902; font-style: italic } /* Comment.Multiline */
.cp { color: #8F5902; font-style: italic } /* Comment.Preproc */
.cpf { color: #8F5902; font-style: italic } /* Comment.PreprocFile */
.c1 { color: #8F5902; font-style: italic } /* Comment.Single */
.cs { color: #8F5902; font-style: italic } /* Comment.Special */
.gd { color: #A40000 } /* Generic.Deleted */
.ge { color: #000; font-style: italic } /* Generic.Emph */
.ges { color: #000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.gr { color: #EF2929 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #00A000 } /* Generic.Inserted */
.go { color: #000; font-style: italic } /* Generic.Output */
.gp { color: #8F5902 } /* Generic.Prompt */
.gs { color: #000; font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #A40000; font-weight: bold } /* Generic.Traceback */
.kc { color: #204A87; font-weight: bold } /* Keyword.Constant */
.kd { color: #204A87; font-weight: bold } /* Keyword.Declaration */
.kn { color: #204A87; font-weight: bold } /* Keyword.Namespace */
.kp { color: #204A87; font-weight: bold } /* Keyword.Pseudo */
.kr { color: #204A87; font-weight: bold } /* Keyword.Reserved */
.kt { color: #204A87; font-weight: bold } /* Keyword.Type */
.ld { color: #000 } /* Literal.Date */
.m { color: #0000CF; font-weight: bold } /* Literal.Number */
.s { color: #4E9A06 } /* Literal.String */
.na { color: #C4A000 } /* Name.Attribute */
.nb { color: #204A87 } /* Name.Builtin */
.nc { color: #000 } /* Name.Class */
.no { color: #000 } /* Name.Constant */
.nd { color: #5C35CC; font-weight: bold } /* Name.Decorator */
.ni { color: #CE5C00 } /* Name.Entity */
.ne { color: #C00; font-weight: bold } /* Name.Exception */
.nf { color: #000 } /* Name.Function */
.nl { color: #F57900 } /* Name.Label */
.nn { color: #000 } /* Name.Namespace */
.nx { color: #000 } /* Name.Other */
.py { color: #000 } /* Name.Property */
.nt { color: #204A87; font-weight: bold } /* Name.Tag */
.nv { color: #000 } /* Name.Variable */
.ow { color: #204A87; font-weight: bold } /* Operator.Word */
.pm { color: #000; font-weight: bold } /* Punctuation.Marker */
.w { color: #F8F8F8 } /* Text.Whitespace */
.mb { color: #0000CF; font-weight: bold } /* Literal.Number.Bin */
.mf { color: #0000CF; font-weight: bold } /* Literal.Number.Float */
.mh { color: #0000CF; font-weight: bold } /* Literal.Number.Hex */
.mi { color: #0000CF; font-weight: bold } /* Literal.Number.Integer */
.mo { color: #0000CF; font-weight: bold } /* Literal.Number.Oct */
.sa { color: #4E9A06 } /* Literal.String.Affix */
.sb { color: #4E9A06 } /* Literal.String.Backtick */
.sc { color: #4E9A06 } /* Literal.String.Char */
.dl { color: #4E9A06 } /* Literal.String.Delimiter */
.sd { color: #8F5902; font-style: italic } /* Literal.String.Doc */
.s2 { color: #4E9A06 } /* Literal.String.Double */
.se { color: #4E9A06 } /* Literal.String.Escape */
.sh { color: #4E9A06 } /* Literal.String.Heredoc */
.si { color: #4E9A06 } /* Literal.String.Interpol */
.sx { color: #4E9A06 } /* Literal.String.Other */
.sr { color: #4E9A06 } /* Literal.String.Regex */
.s1 { color: #4E9A06 } /* Literal.String.Single */
.ss { color: #4E9A06 } /* Literal.String.Symbol */
.bp { color: #3465A4 } /* Name.Builtin.Pseudo */
.fm { color: #000 } /* Name.Function.Magic */
.vc { color: #000 } /* Name.Variable.Class */
.vg { color: #000 } /* Name.Variable.Global */
.vi { color: #000 } /* Name.Variable.Instance */
.vm { color: #000 } /* Name.Variable.Magic */
.il { color: #0000CF; font-weight: bold } /* Literal.Number.Integer.Long */
update models.py
at the top under the includes, add:
import markdown_extensions.glightboxify
add to Post class:
def get_image(self):
try:
my_json = json.loads(self.json)
image = self.replace_static(my_json['image'])
except KeyError:
image=None
except TypeError:
image=None
return image
def get_summary(self):
try:
my_json = json.loads(self.json)
summary=my_json['summary']
except KeyError:
summary=None
except TypeError:
summary=None
return summary
def gen_preview_text(self):
return self._render_markdown(' '.join(self.content[:200].split(' ')[:-1][:15])+' ...')['html']
def summary_or_short_generated_preview(self):
summary = self.get_summary()
if not summary:
summary=self.gen_preview_text()
return summary
def get_preview_text(self):
if self.can_be_split():
return self.render_split_markdown()['html']
else:
return self.gen_preview_text()
@staticmethod
def split_content(markdown):
kernel = re.compile('<!-- *split *-->')
results = kernel.search(markdown)
if results is not None:
return markdown[:results.start()]
else:
return markdown
def can_be_split(self):
markdown = self.content
kernel = re.compile('<!-- *split *-->')
results = kernel.search(markdown)
if results is not None:
return True
else:
return False
def replace_static(self,text):
text = re.sub(RELFIND_CORE,RELREPLACE1_CORE+self.get_relpath()+'/'+RELREPLACE2_CORE,text)
text = re.sub(ABSFIND_CORE,ABSREPLACE_CORE,text)
print(text)
return text
def render_split_markdown(self):
return self._render_markdown(self.split_content(self.content))
Update the _render_markdown() method
update the line that says:
md_ex.extend([
markdown_extensions.find_replace_pre.FindReplaceExtension(find=RELFIND,replace=RELREPLACE1+self.get_relpath()+'/'+RELREPLACE2,priority=202,name='rel-find-replace'),
markdown_extensions.find_replace_pre.FindReplaceExtension(find=ABSFIND,replace=ABSREPLACE,priority=201,name='abs-find-replace'),
])
adding
markdown_extensions.glightboxify.GlightboxExtension(),
Git Repository
The code for this lecture can be found at the related github repository in its own branch, here:
https://github.com/danb0b/django_homepage_public/tree/Lecture9-style-and-formatting











