Skip to content
PortBay

Django templates, edited where they render

A pip install and one line in INSTALLED_APPS, and every element carries its own file, line and column — through extends, include and block. Your TEMPLATES setting is not touched. Pro, early access, opt-in.

The short answer

How do I edit Django templates visually?

Editing a Django template visually needs the rendered page to remember where it came from. By the time the browser has the HTML, the extends chain, the included partials and the block overrides have collapsed into one document with nothing left to say which file wrote which line. The block editors in this space avoid the problem rather than solving it, by storing content as data instead of touching templates. Recovering the mapping means hooking the one point every Django template passes through and stamping each element with its file, line and column as the template is constructed. PortBay ships that as a PyPI package, portbay-django-stamper, and edits are byte-spliced back into the template file. Measured on served HTML against a zero-stamp control: 18 of 18 coordinates exact on Django 6.1 and 5.2.17.

Verified against the product, 2026-09-05.

In the app

A Django project, running and clickable

acme-shop · Board6 cards3 agents online
Pending2
infra
Rate-limit the API
P1
Dark mode polish
P2
Todo2
auth
Add OAuth login
P0Claude Code0/3oauth-login
Auto-dispatching
implement OAuth on app.test
db
Migrate to Postgres
P1
In Progress1
Fix flaky checkout test
P0
Done2
Set up Mailpit inbox
P2
Seed demo data
P2
1/5 · AssignA card lands in Todo and @claude is mentioned

PortBay runs your Django app at its own .test URL with trusted HTTPS and a per-project PostgreSQL or MySQL database, and dispatches board cards into it. The visual editor edits that same running app.

Walkthrough

From click to template file

Four steps. Step three has two parts, and skipping the second is the one mistake that leaves you with a package installed and nothing stamped.

  1. Install PortBay and add your Django project
  2. Turn the visual editor on
  3. Install the package, then register the app
  4. Open Edit in browser and change something

Install PortBay and add your Django project

Homebrew installs the app and the bundled portbay CLI. Add the project folder and PortBay detects Django from manage.py at the project root, provisions a database, and serves the app at its own .test hostname over trusted HTTPS.

brew tap portbay-app/portbay && brew install --cask portbay

Turn the visual editor on

It ships to Pro under early access and is off by default. Sign in to Pro, then flip the Early Access toggle. The open-source build does not include the editor at all — it is not compiled in.

Settings › Account › Early Access

Install the package, then register the app

Both halves are required. Django has no package auto-discovery — no equivalent of Laravel's provider discovery or the Rails Railtie — so nothing is stamped until the app is named in INSTALLED_APPS. Watch the spelling: you install portbay-django-stamper with hyphens, and you register portbay_loc with an underscore. It needs Python 3.9 or newer and Django 4.2 or newer.

pip install portbay-django-stamper → INSTALLED_APPS += ["portbay_loc"]

Open Edit in browser and change something

The project's Visual editing section has one button. It opens your normal browser at your normal .test URL with the edit bar docked at the top, booting in Preview mode where the page stays fully interactive. Switch to Edit, double-click text to type into the live page, then Save to write to source.

https://myapp.test
Without PortBay

Why it never touches your TEMPLATES setting

The obvious way to instrument Django templates is to ship a loader. That works, and it costs you a settings block you then own forever — which is why this package does something else.

Instead the package patches the single constructor every Django template passes through — so filesystem, app_directories, cached and locmem loaders are all covered at once, and your APP_DIRS and resolution order stay exactly as you left them.

Questions

Asked before downloading

One entry in INSTALLED_APPS: "portbay_loc". That is the whole configuration. Note the two names differ — the distribution you pip install is portbay-django-stamper with hyphens, and the importable app you register is portbay_loc with an underscore. Installing without registering is the one failure mode that looks like nothing happening, because Django has no package auto-discovery to fall back on.

No, deliberately. Shipping a template loader would have forced you to spell out OPTIONS['loaders'] by hand, which means deleting APP_DIRS and writing out the stock loaders yourself — a settings block you would then maintain forever, and one that silently changes template resolution order if you get it wrong. Instead the package patches the single Template constructor that every loader ends up calling, so your loaders and APP_DIRS stay exactly as they are.

Yes, and each element points at the file it was actually written in rather than the file it rendered through. A block defined in a child template and rendered into a base points at the child; an included partial points at the partial. On served HTML measured against a zero-stamp control, 18 of 18 coordinates were exact on both Django 6.1 and 5.2.17, covering an extends base, a child block, an included partial and a for loop over an include.

Yes. An htmx fragment is markup your server rendered through the same stamped templates, so the coordinates travel with the response — an htmx-style fragment measured 2 of 2 exact in the same run. Fragments assembled on the client, which the server never saw, are a different matter and fall back to text search.

Templates that are not .html or .htm, templates with no file behind them, and templates that live outside your project — a third-party app's templates get no coordinate. The reasoning is that a coordinate pointing into a file you cannot edit is worse than no coordinate at all, so those elements fall back to the text-search tier instead of claiming a precision they do not have.

No. The stamp is applied to the template source as a string in memory, on its way into Django's Template constructor — the file on disk is never opened for writing, so no data-pb-loc attribute ever reaches your repository. Stamping is on when DEBUG is on, and PORTBAY_LOC=0 or 1 overrides it either way; the shell form works, because manage.py runserver passes its whole environment through to the child process.

No. It is a Pro feature, still in early access behind an opt-in toggle in Settings, and it is not compiled into the open-source build at all. It is also unavailable on a project while that project is publicly tunneled — the edit bar and its write-back endpoints are never routed onto public traffic. Running Django, the database, the .test hostname and trusted HTTPS are all in the free, open-source app.

PortBay mascot — a friendly blue tugboat

Give your projects and your agents a real local home.

Download for macOS

Free & open source · macOS 11+ on Apple Silicon · Pro from $10/mo