I love Django—it covers pretty much everything I need in a web environment. However, when it comes time to deploy a project to production, there are always a bunch of pre-deployment checks, and I can never seem to remember them all. I find myself constantly revisiting the official Django deployment checklist page.
Today I realized I don’t need all the detailed information every time—just a simple reminder list is enough. So, I built an interactive Django deployment checklist using Great Tables in marimo and hosted it on marimo.app. Now I can interact with it whenever I need a quick double-check.

marimo
The widgets may take a few moments to load, as they rely on WebAssembly under the hood.
- I asked AI to generate a checklist and wrapped it in a Polars
DataFramecalleddf. - I created 10 switch widgets and stacked them into an array widget named
status_widgetsto represent the status of each checklist item. - I extracted the HTML representation of each widget via its
_repr_html_()method and inserted it as a new"Status"column indf, which I then wrapped in a Great Tables GT object. - I added two source notes using GT.tab_source_note()—one to display progress, and another for a visual progress bar.
- Finally, I gave the table a nice header with GT.tab_header() and applied some styling using GT.opt_stylize().
| ✅ Django Deployment Checklist | ||
| Status | Task | Notes |
|---|---|---|
| Set DEBUG = False | Never deploy with DEBUG = True ⚠️ | |
| Configure ALLOWED_HOSTS | Include your domain(s) or IP address 🌐 | |
| Set up a secret key | Use a strong, secure key from an environment variable 🔐 | |
| Collect static files | Run `python manage.py collectstatic` 📦 | |
| Apply database migrations | Run `python manage.py migrate` 🗃️ | |
| Set up gunicorn or uWSGI | Use as a WSGI server in production 🔄 | |
| Configure reverse proxy (e.g., Nginx) | Serve static/media files and forward to WSGI server 🧭 | |
| Secure the database | Use strong credentials, disable remote root login 🛡️ | |
| Set up HTTPS (SSL) | Use Let's Encrypt or your own certificate 🔒 | |
| Configure logging & monitoring | Track errors and app performance 📊 | |
| 0 / 10 | ||
| |
||
Check out the full marimo code below or view it on molab.
import marimo
__generated_with = "0.14.7"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import polars as pl
from great_tables import GT, html, md
return GT, html, pl
@app.cell
def _(pl):
tasks = [
"Set DEBUG = False",
"Configure ALLOWED_HOSTS",
"Set up a secret key",
"Collect static files",
"Apply database migrations",
"Set up gunicorn or uWSGI",
"Configure reverse proxy (e.g., Nginx)",
"Secure the database",
"Set up HTTPS (SSL)",
"Configure logging & monitoring",
]
notes = [
"Never deploy with DEBUG = True ⚠️",
"Include your domain(s) or IP address 🌐",
"Use a strong, secure key from an environment variable 🔐",
"Run `python manage.py collectstatic` 📦",
"Run `python manage.py migrate` 🗃️",
"Use as a WSGI server in production 🔄",
"Serve static/media files and forward to WSGI server 🧭",
"Use strong credentials, disable remote root login 🛡️",
"Use Let's Encrypt or your own certificate 🔒",
"Track errors and app performance 📊",
]
n_row = len(tasks)
status = ["☐"] * n_row
data = {"Status": status, "Task": tasks, "Notes": notes}
df = pl.DataFrame(data)
return df, n_row
@app.cell
def _(mo, n_row):
status_widget = mo.ui.switch()
status_widgets = mo.ui.array([status_widget] * n_row)
return (status_widgets,)
@app.function
def create_bar(
x: float,
max_width: int,
height: int,
background_color1: str,
background_color2: str,
) -> str:
width = round(max_width * x, 2)
px_width = f"{width}px"
return f"""\
<div style="width: {max_width}px; background-color: {background_color1};">\
<div style="height:{height}px;width:{px_width};background-color:{background_color2};"></div>\
</div>\
"""
@app.cell
def _(GT, df, html, n_row, pl, status_widgets):
done_count = sum(s.value for s in status_widgets)
gt = (
GT(
df.with_columns(
pl.Series(
[status._repr_html_() for status in status_widgets]
).alias("Status")
)
)
.tab_source_note(f"{done_count} / {n_row}")
.tab_source_note(
html(
create_bar(
done_count / n_row,
max_width=750,
height=20,
background_color1="lightgray",
background_color2="#66CDAA",
)
)
)
.tab_header("✅ Django Deployment Checklist")
.opt_stylize(color="cyan", style=4)
)
gt
return
if __name__ == "__main__":
app.run()- This table is for demonstration purposes only. You should customize it based on your own needs.
- This post was drafted by me, with AI assistance to refine the content.