A customizable Django foundation with Tailwind CSS, HTMX, Loguru logging, and streamlined user management. Includes ready-to-use JavaScript modules for enhanced frontend interactivity.
This project is a work in progress, but feel free to use it and provide feedback! Contributions are welcome.
There is a lot to re-do, and a lot of docs to write, especially for navigation and user management. I'm working on it.
git clone https://github.com/smattymatty/Base-Django-HTMX-Tailwind
cd Base-Django-HTMX-Tailwind
python -m venv venv
source venv/bin/activate # Linux/macOS
.\venv\Scripts\activate # Windows (Note: Use `.\` instead of `source`)
pip install -r requirements.txt
# credentials.py
# SECURITY WARNING:
# Replace the following placeholder with a strong, unique secret key for your Django project.
# You can generate one using:
# python -c "import secrets; print(secrets.token_urlsafe(50))"
SECRET_KEY = '' # Replace this with your actual secret key
# Database configuration
# NOTE: This is a sample SQLite configuration for initial setup and testing.
# For production or more robust development, replace it with your actual database settings (e.g., PostgreSQL).
DATABASE = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'mydatabase', # Replace with your database name (optional)
}
# Optional: Add more credentials here for other services or APIs
# Example:
# API_KEY = 'your_api_key'
SECRET_KEY
: Replace the placeholder SECRET_KEY = '' with a strong, unique secret key for your Django project. You can generate one using: python -c "import secrets; print(secrets.token_urlsafe(50))"
DATABASE
: Replace the placeholder with your actual database settings (e.g., PostgreSQL), or use the sample SQLite configuration for initial setup and testing.Run Migrations:
python manage.py migrate
Create Superuser:
python manage.py createsuperuser
Run Server:
python manage.py runserver
# or
.\run_dev.bat # Windows
run_dev.sh # Linux/macOS
This project is already configured to use Tailwind and HTMX. It uses the popular third-party packages Django-Tailwind and Django-HTMX to integrate these technologies into the project.
# settings.py
INSTALLED_APPS = [
...
'django_htmx',
'tailwind',
'theme',
...
]
base.html
, which all pages inherit from, includes the following lines:
{% load static tailwind_tags django_htmx %}
<!DOCTYPE html>
<html lang="en">
<head>
{% tailwind_css %}
<!-- Bootstrap Icons -->
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" />
<meta charset="UTF-8" />
<title>
{% block title %}{{ title }}{% endblock %}
</title>
<script src="{% static 'BaseApp/htmx.min.js' %}" defer></script>
{% django_htmx_script %}
</head>
The {% tailwind_css %}
tag is used to include the Tailwind CSS stylesheet in the HTML document.
The {% django_htmx_script %}
tag is used to include the HTMX script in the HTML document.
Run the command:
./tailwind_run.bat # Windows
./tailwind_run.sh # Linux/macOS
To start the Tailwind CSS development server provided by the 'Django-Tailwind' package.
This project utilizes Loguru, a powerful and flexible logging library for Python, to provide a structured and efficient logging system.
The main Loguru configuration is located in the BaseApp/utils.py
file. It includes:
get_module_logger
: This function is used to create a logger instance for a specific module.from .constants import LOG_FORMAT
: The log format includes the timestamp, log level, module name, and the log message. This lies in the BaseApp/constants.py
file.#constants.py
LOG_FORMAT = "{time} -- {level} -- {function} -- line {line}\n\t {message}"
from BaseApp.utils import get_module_logger
logger = get_module_logger("my_module", __file__)
This line creates a logger instance bound to the "my_module" module and the file where the logger is being used.logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
logger.error("This is an error message")
logger.critical("This is a critical message")
CustomUserManager
# In your managers.py file:
from BaseApp.utils import get_module_logger
module_logger = get_module_logger("managers", __file__)
# ... later in your code ...
module_logger.debug(f"Creating user with username: {username} and email: {email}")
In this example, module_logger logs a debug message when a new user is being created. This helps you track user creation activities.
This project provides a collection of JavaScript modules designed to supercharge your Django templates with interactive features, without the need for any custom JavaScript code. Simply load the corresponding template tags, add some data attributes to your HTML elements, and let the magic happen!
[button_example_1]](BaseApp/ui_elements/partials/button_example_1.html) for an example.
The
ToggledButtonGroup
class allows you to create interactive button groups where only one button can be active at a time. Clicking a button toggles its active state. You can customize the appearance of active buttons, choose the initially active button, and easily manage multiple button groups on your page.
{% load button_group_tags %}
<form id="myButtonGroup-toggled-button-group">
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</form>
load the button_group_tags
template tag
Create a container with an ID ending in "-toggled-button-group".
hx-post
integration.Place your buttons inside this container.
myButtonGroup
: The ID of the button group container.
<form id="myButtonGroup-toggled-button-group"
data-active-class="bg-blue-500 text-white"
data-initial-active="2">
</form>
data-active-class
: Specifies the CSS class(es) to apply to the active button. You can include multiple classes separated by spaces (e.g., bg-blue-500 text-white).
data-initial-active
: Determines which button should be active when the page loads. It can be:
<div id="myButtonGroup-toggled-button-group">
...
</div>
{% init_button_groups "myButtonGroup" %}
{% init_button_groups %}
or you can initialize a specific button groups with {% init_button_groups "name1" "name2" "name3" %}
.The ToggledButtonGroup class seamlessly integrates with HTMX. When your buttons include the hx-get attribute, HTMX will automatically handle fetching and updating the content based on the initially active button (as specified by the data-initial-active attribute).
hx-get
: Specifies the URL to fetch when the button is clicked.hx-target
: Specifies the element on the page to update with the content returned by the HTMX request.hx-swap
: Specifies how the returned content should be swapped into the target element (e.g., "innerHTML", "outerHTML", "beforeend").Example:
<div id="myButtonGroup-toggled-button-group"
data-initial-active="random">
<button hx-get="/get-content-1"
hx-target="#contentArea"
hx-trigger="mousedown">
Button 1
</button>
<button hx-get="/get-content-2"
hx-target="#contentArea"
hx-trigger="mousedown">
Button 2
</button>
<button hx-get="/get-content-3"
hx-target="#contentArea"
hx-trigger="mousedown">
Button 3
</button>
</div>
<div id="contentArea"></div>
In this example, the initial active button is randomly selected, and will automatically perform the first HTMX request when the page loads.
The ToggledButtonGroup class automates sending POST requests using HTMX when a button in the group is initially activated.
<form id="myButtonGroup-toggled-button-group">
{% csrf_token %}
...
</form>
hx-post
attribute to your button group:<button hx-post="{% url 'BaseApp:display_number' %}"
hx-trigger="click"
hx-target="#result-container"
hx-swap="innerHTML"
name="number"
value="0"
class="...">
Button
</button>
<button hx-post="{% url 'BaseApp:display_number' %}"
hx-trigger="click"
hx-target="#result-container"
hx-swap="innerHTML"
name="number"
value="1"
class="...">
Button
</button>
hx-post
: This attribute indicates that an HTTP POST request should be sent when the button is clicked. You'll specify the URL of your Django view function that handles the request.
name
: This attribute specifies the name of the form field that will be submitted with the POST request.
value
: This attribute specifies the value of the form field that will be submitted with the POST request.
@require_POST def display_number(request): # Retrieve the button value from the POST data number = request.POST.get('number') # Render the template with the number template = loader.get_template('BaseApp/tests/number_display.html') context = {'number': number} return HttpResponse(template.render(context, request))
**Full Example:**
```html
{% load button_group_tags %}
<div id="myButtonGroup-toggled-button-group"
data-active-class="bg-blue-500 text-white" data-initial-active="random">
<button hx-post="{% url 'BaseApp:display_number' %}"
hx-trigger="mousedown"
hx-target="#result-container"
hx-swap="innerHTML"
name="number"
value="0"
class="...">
Button 0
</button>
<button hx-post="{% url 'BaseApp:display_number' %}"
hx-trigger="mousedown"
hx-target="#result-container"
hx-swap="innerHTML"
name="number"
value="1"
class="...">
Button 1
</button>
<button hx-post="{% url 'BaseApp:display_number' %}"
hx-trigger="mousedown"
hx-target="#result-container"
hx-swap="innerHTML"
name="number"
value="2"
class="...">
Button 2
</button>
</div>
<div id="result-container"></div>
{% init_button_groups "myButtonGroup" %}
How it Works