From-Scratch Build · Academic Web
A self-hosted personal site for a researcher — publications, projects, talks and courses — where every word is editable from an admin panel instead of hand-coded HTML. Rebuilt from scratch to understand how a database-backed Django site is actually wired together.
What it is
Most academic homepages are static HTML that goes stale the moment you give a new talk or publish a new paper. This is the opposite: a content-managed personal site where publications, projects, research lines, talks and courses all live in a database, and the owner edits them through a private admin instead of touching code.
I built it to learn the full server-rendered web model — not a single-page app, but classic Django: a request comes in, a view queries the database, a template renders HTML, and the browser gets a finished page. The only sprinkle of interactivity comes from htmx, which lets sections of a page update without a full reload.
The core idea I wanted to learn: the content and the presentation should be separate. The same template renders whether there are three publications or three hundred — the page is a view of a database, not a hand-written document.
The stack
The point of this rebuild was the toolchain. Here is what each piece actually does in the system.
The Python web framework that does the heavy lifting — URL routing, the ORM, templating, and a generated admin site for editing content.
Each content type — Publication, Project, Talk, Course, ResearchLine — is a Python class. Django turns it into a table and into admin forms automatically.
Adds AJAX to plain HTML via attributes. Filtering a publication list swaps in just the new rows instead of reloading the whole page.
Long-form text (bios, project write-ups) is authored in Markdown and rendered to HTML, so the admin doesn't have to write tags by hand.
A single-file database for content, with Pillow handling uploaded images — banners, project shots and profile photos.
The whole app — Python, dependencies, the database file — ships in one container, so it runs identically on a laptop or a server.
Architecture
Every page follows the same server-rendered path. Tracing it once made the whole framework click.
A path like /publications/ is matched against a URL map and handed to the matching view function.
The view asks the database for the records it needs — all talks, this year's papers — through Django's ORM, no raw SQL.
The data is poured into an HTML template that extends a shared base.html layout.
Filtered lists render a small partial template and htmx swaps it into the page — no full reload.
The site owner logs into Django's admin to add a paper or edit a bio; the public pages update instantly.
A generated sitemap and per-page metadata so search engines can index the researcher's work.
How it runs
The build is designed so a non-technical owner never sees the code. The workflow is:
docker compose up starts Django, applies migrations and serves the site.In my rebuild I focused on getting the model layer right first — because in Django, once the models are sound, the admin, the views and the templates all fall out of them.
Reflection
models.py.