Django, Flask and FastAPI
Next release
How midcode starts a Django, Flask or FastAPI site with the project's own Python, edits its templates on the canvas, and where pages and styles come from.
This ships with the next release of midcode. The version you can download today (1.1.2) doesn’t have it yet.
midcode opens a Django, Flask or FastAPI project, starts it with the project’s own Python, and edits the HTML written in its templates: text, classes, attributes, new elements and their order. What the template language works out ({{ post.title }}, {% for %}, a form Django renders) is left to your code.
Python renders the page, so midcode finds each element in your templates after the page loads. Sites a server renders explains how that works and what it means for editing.
At a glance
| Django, Flask and FastAPI | |
|---|---|
| Detected by | manage.py (Django); a Flask(…) or FastAPI(…) app in a project that depends on that package |
| Runs with | manage.py runserver, flask run --debug or uvicorn --reload, with the project’s own Python |
| Elements are marked by | midcode, after each page loads, by matching it against the project’s templates |
| Editing | Text, classes, attributes and tag; insert, move, duplicate and remove |
| Pages | Django’s urls.py, Flask’s @app.route. FastAPI: type the path |
| Styles | Tailwind 4 classes, or mid: utilities with midcode.css in the static folder (Django, Flask) |
| Tried with | Django with its .venv, Flask, and FastAPI with Jinja. Every element written in the templates was found |
How midcode runs it
| Stack | Recognised by | Command |
|---|---|---|
| Django | manage.py at the top of the folder | <python> manage.py runserver 127.0.0.1:$PORT |
| Flask | The project depends on flask, and a file makes the app: app = Flask(__name__) | <python> -m flask --app <module> run --debug --host 127.0.0.1 --port $PORT |
| FastAPI | The project depends on fastapi, and a file makes the app: app = FastAPI() | <python> -m uvicorn <module>:<name> --reload --host 127.0.0.1 --port $PORT |
$PORT is a free port midcode picks. The command runs in your login shell, in the project’s folder, and what it prints is in the Dev server log in the top bar. Nothing in the project is changed to run it.
“Depends on” means the package is named in requirements.txt, requirements/base.txt, requirements/dev.txt, pyproject.toml, Pipfile or setup.py. For Flask, an app.py that imports it is enough.
The app is looked for in the .py files at the top of the project (app.py, main.py, wsgi.py, asgi.py, application.py, run.py and server.py first) and one folder in (<folder>/__init__.py, app.py, main.py). For Flask, a create_app() or make_app() factory counts too. For FastAPI the app has to be assigned to a name.
--debug makes Flask read your templates and code again when they change. --reload restarts Uvicorn when your code changes.
Which Python
midcode uses the first of these it finds:
The project’s virtual environment:
.venv/bin/python,venv/bin/pythonorenv/bin/python.uv run python, when there’s auv.lock.poetry run python, when there’s apoetry.lock.pipenv run python, when there’s aPipfile.python3from your shell.
So a Django project with a .venv runs as .venv/bin/python manage.py runserver 127.0.0.1:$PORT.
What you need
Python and the project’s packages installed, and the site in a state where it runs (its database migrated, its settings in place). midcode doesn’t run pip install or migrate on a project it opens.
New project makes a Django or a Flask site with its own .venv, a templates/ and a static/ folder.
What you can edit
Anything written as HTML in a template. In Django’s and Jinja’s templates, {{ }} and {% %} are never touched, and {# #} is a comment.
{% extends "base.html" %}
{% block content %}
<section class="hero">
<h1>Fresh bread, every morning</h1>
{% include "partials/hours.html" %}
{% for loaf in loaves %}
<article class="loaf"><h2>{{ loaf.name }}</h2></article>
{% endfor %}
</section>
{% endblock %}The heading is written here: double-click it on the canvas to change it.
What
base.htmlandpartials/hours.htmlwrite is edited in those files. The right panel shows which file and line an element comes from, under Code.The
<article>is one line shown once per loaf: a class you add applies to all of them. The loaf’s name is the template’s to print.
-<section class="hero">- <h1>Fresh bread, every morning</h1>+<section class="hero mid:p-6">+ <h1>Bread, pastries and coffee</h1>After an edit midcode reloads the page in every breakpoint.
Pages
Pages in the top bar is filled from your routes, read as text (nothing is run):
Django: the
ROOT_URLCONFof the settings module thatmanage.pynames. Everypath("about/", …)is a page.include("blog.urls")is followed, under its prefix, up to three levels. The admin and Django’s own includes are left out.<int:id>makes a dynamic page, shown as[id].Flask: every
@app.route("/about")or@bp.route(…)in the project’s.pyfiles, up to three folders deep. A route that only takesPOSTisn’t a page.<name>and<int:id>are dynamic.FastAPI: not read. Type a path in Pages and press Enter.
Where it can, midcode also knows the template behind a page: TemplateView.as_view(template_name="home.html") or the render(request, "home.html") of the view a Django route names, and the render_template("home.html") of a Flask view. Templates are looked for in templates/ and in <app>/templates/.
A dynamic page finds its real addresses from the running site’s sitemap and links (Pages and navigation).
midcode doesn’t add pages here: in Django, Flask and FastAPI a page is a route and a view written in Python, yours or your agent’s to write.
Site settings
The globe in the top bar opens Site settings. The title, the description, the language, search engines, the favicon and the social image are written as tags in the <head> of a template: the first one that closes a <head>, in alphabetical order of its path (often templates/base.html).
What the template computes there (<title>{% block title %}Bakery{% endblock %}</title>) shows as code and isn’t written. Images are copied to the same folder as midcode.css (the table below). In a FastAPI project, or a Django one without STATICFILES_DIRS, midcode has no such folder (unless the project has a public/ one) and asks you to put the image where the site serves it and link it in the code. This wasn’t tried on a Django, Flask or FastAPI site.
Styles
With Tailwind 4 in the project, midcode writes Tailwind’s classes. It starts only the web server: if a separate command compiles your CSS, keep it running yourself.
Without Tailwind, midcode writes mid: utilities and keeps their CSS in midcode.css (Without Tailwind). Where the file goes depends on the stack:
| Stack | midcode.css goes in | Linked as |
|---|---|---|
| Flask | static/ beside the app, or <package>/static/ when the app is a package | /static/midcode.css |
| Django | The folder that STATICFILES_DIRS names in the settings file | Under STATIC_URL, for example /static/midcode.css |
| FastAPI | The top of the project, or src/ when there is one | Not linked: add the <link> yourself |
On your first style edit, every template that closes a <head> gets the link, as one undoable step:
<link rel="stylesheet" href="{% static 'style.css' %}">+ <link rel="stylesheet" href="/static/midcode.css"> </head>The link is a plain path, not {% static %}. If your production site serves static files from another address, change that line to {% static 'midcode.css' %}.
In Django, midcode reads STATICFILES_DIRS and STATIC_URL from the settings file that manage.py names. If that file doesn’t set STATICFILES_DIRS, or the folder doesn’t exist, midcode writes midcode.css at the top of the project and says it couldn’t tell where to import it.
Limits
Text the template prints, including
{% translate "…" %}, isn’t editable on the canvas.HTML that Python builds (
{{ form.as_p }}, a widget, the Django admin) isn’t written in your templates, so it isn’t found.Templates inside the virtual environment are never read.
Django’s
re_path()and routes built in code aren’t listed. A Flask blueprint’surl_prefixisn’t added to its routes.If the project’s
package.jsonlists Vite or another framework midcode knows, the folder opens as that kind of project and its templates aren’t matched.A virtual environment is the path that was tried.
uv, Poetry and Pipenv are chosen by their lockfile and weren’t tried. Neither were settings split across several files.The free canvas is for Next.js projects.
Troubleshooting
“No module named django” (or flask, uvicorn) in the log. midcode picked a Python that doesn’t have the project’s packages. Put the environment in .venv at the top of the project, or set the command yourself.
midcode asks “How does this site run?”. It didn’t find where the Flask or FastAPI app is made, for example because it’s deeper than one folder in. Type the command and the address. $PORT is the port midcode picked. They’re saved in .midcode/server.json:
{
"command": "uv run uvicorn src.shop.main:app --reload --host 127.0.0.1 --port $PORT",
"url": "http://127.0.0.1:$PORT"
}A Django error page about the database. The site is running and needs its migrations. Run them in a terminal, then press Reload breakpoints.
The site runs in Docker. Leave the command empty and give midcode the address where it answers. The templates on your Mac are matched the same way (Any other stack).