3 horizontal lines, burger
3 horizontal lines, burger

3 horizontal lines, burger
Remove all
LOADING ...

Generator of table of contents for Django website’s articles

Clock
25.04.2025
/
Clock
12.02.2026
/
Icon of app type
Django app
An eye
505
Hearts
0
Connected dots
0
Connected dots
0
Connected dots
0

Kind of Django app:
Middleware

Description

This tool is a Django application that generates the "Table of contents" of the page on which it is installed. Due to the peculiarity of the Django framework, all generation occurs on the server, that is, the SSR rendering method. This application also creates anchor links to the collected chapters, if the heading have an id attribute.

Instalation and Setting up

Let's start by installing the necessary package, my package. You can download it here, but let's download it from PyPi. Don't forget to install the virtual environment and activate it accordingly.
pip install django-simple-toc
Now let's set up the project. In the settings.py file, connect the application and the corresponding middleware:
INSTALLED_APPS = [ ... 'django_simple_toc', ... ] MIDDLEWARE = [ ... 'django_simple_toc.middleware.TableofcontentMiddleware', ... ]
And now, in order for this application to find pages to add "Table of Contents" to, your views will need to return a TemplateResponse object. For example, I have a standard article view that returns an HttpResponse using the render shortcut function:
from django.shortcuts import render def article(request): ... return render(request, template_name, context)
Instead of the render function, you need to substitute TemplateResponse. Like this:
from django.template.response import TemplateResponse def article(request): ... return TemplateResponse(request, template_name, context)
We are done with setting up and installing the necessary django application. Now, about how and where to insert the "TableOfContent" template.

A usage guide

Choose the required template and the place where your article index will be. I usually insert the article index block at the very beginning. After that, you need to insert a piece of the template like this:
{% if isTableOfContentMiddlewareConnected %} {% include 'table-of-content.html' with NO_REF='False' LIST_STYLE='none' WITH_HEADER_TYPE='True' WITH_PADDING='True' WITH_TITLE='Index' DISALLOWED_TAGS='h1,h6' DISALLOWED_HEADERS='Вам так же может понравится, Ссылки и источники' %} {% endif %}
Here, you can see all available template variables that are used to customize and tune the article content block. More about them in the next chapter.

Template context variables for customization

  1. NO_REF - valid values, True, False. Determines whether an internal anchor link of the chapter will be created. Links will only be created if the id attribute is specified in the corresponding headings.
  2. LIST_STYLE - valid values, all currently supported by the list-style-type style. Which list icons to use.
  3. WITH_HEADER_TYPE - valid values, True, False. Determines whether the tag name (h1, h2, h3, h4, h5, h6) will be added before the element.
  4. WITH_PADDING - valid values, True, False. Determines whether there will be indents
  5. WITH_TITLE - valid values, any string. If not defined, default value will be used: Table of content
  6. DISALLOWED_TAGS - allowed values, string containing h1, h2, h3, h4, h5, h6. Determines which headings to include and which not, depending on the tag name.
  7. DISALLOWED_HEADERS - valid values, string containing any heading content. Determines which headers to include and which not to include, depending on the contents of the header.
  8. isTableOfContentMiddlewareConnected - to ensure that django-simple-toc is connected properly

CSS classes for additional customization

By default, these styles do nothing, they are for the users of the package. If they want to change the appearance of the block. Here are the classes for styling:
  1. toc-title
  2. toc-list-container
  3. toc-list-item
  4. toc-list-tag-name
  5. toc-list-tag-content

How it works

Now that you know how to install and use it, you might want to learn how it works. Well, I wouldn't say it's that complicated, but it's still useful to know what you're installing.
So, I implemented it as a Django app, with a little middleware, or shim between the final rendered template and other middleware. Here's the middleware code:
from bs4 import BeautifulSoup from django.template.response import TemplateResponse class TableofcontentMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) return response def process_template_response(self, request, response: TemplateResponse): soup = BeautifulSoup(response.rendered_content, 'lxml') headers_tags = ('h1', 'h2', 'h3', 'h4', 'h5', 'h6') headers = soup.find_all(headers_tags) toc_headers = [] for header in headers: toc_headers.append({ 'name': header.name, 'content': header.text, 'ref': header.get('id'), 'padding': int(header.name[1:]) * 2 }) response.context_data.update({'isTableOfContentMiddlewareConnected': True}) response.context_data.update({'toc_headers': toc_headers}) return response
I override 3 methods. We are not interested in the __init__ and __call__ methods, because this is the minimum code required for this package to be able to work. The only thing I will say is that the __init__ method is executed once when the project is launched, and there you can define common class members for further work.
The process_template_response method is called immediately after a particular view (be it a function-based or a class-based) returns an object of the TemplateResponse class. This is why it was necessary to redesign the article view in the beginning.
In the function itself, we parse the rendered content and find all the heading tags. After that, we go through them and update the context data storage.
There are two templates used by this application, table-of-content.html:
{% load static %} {% if WITH_TITLE %} <h2 class="toc-title"><b> {{WITH_TITLE}} </b></h2> {% else %} <h2 class="toc-title"><b> Table of content </b></h2> {% endif %} <ol class="toc-list-container"> {% for header in toc_headers %} {% if header.name not in DISALLOWED_TAGS and header.content not in DISALLOWED_HEADERS %} <li class="toc-list-item" style="list-style-type: {{LIST_STYLE}}; {% if WITH_PADDING == 'True' %} padding-left: {{header.padding}}px; {% endif %} "> {% if NO_REF != 'True' %} {% if header.ref %} <a href="#{{header.ref}}"> {% include 'table-of-content-element.html' with WITH_HEADER_TYPE=WITH_HEADER_TYPE %} </a> {% else %} {% include 'table-of-content-element.html' with WITH_HEADER_TYPE=WITH_HEADER_TYPE %} {% endif %} {% else %} {% include 'table-of-content-element.html' with WITH_HEADER_TYPE=WITH_HEADER_TYPE %} {% endif %} </li> {% endif %} {% endfor %} </ol>
And table-of-content-element.html respectively:
{% if WITH_HEADER_TYPE == 'True' %} <span class="toc-list-tag-name">{{header.name}}</span> - {% endif %} <b> <span class="toc-list-tag-content">{{header.content}}</span> </b>
What each variable means, you already know from the first chapters.

Similar tools

Django application for managing ad blocks from YAN

Creation date
09.10.2025
/
Update date
08.03.2026
/
Icon of app type
Django app
An eye
243
Hearts
0
Connected dots
0
Connected dots
2
Connected dots
0
Complete guide to installing and configuring Django Yandex Ad Manager for advanced advertising integration. Learn to implement banners, full-screen ads, carousels, and in-image ads with platform targeting, pagination support, and smart middleware injection. Step-by-step setup with code examples for optimal ad placement and monetization.

Breadcrumbs for Django website

Creation date
27.04.2025
/
Update date
12.02.2026
/
Icon of app type
Django app
An eye
504
Hearts
1
Connected dots
0
Connected dots
0
Connected dots
0
This tool is a Django application that generates "Breadcrumbs" of the page it is installed on. Due to the peculiarity of the Django framework, all generation occurs on the server, i.e. SSR rendering method.

Do not forget to share, like and leave a comment :)

Reviews

(0)

captcha
Send
LOADING ...
It's empty now. Be the first (o゚v゚)ノ