Skip to content
Python

Web Dev With Python: What to Learn, in What Order

By The EbookWale Team · Updated July 31, 2026 · 16 min read

Python runs the server side: Django for sites with logins and an admin, Flask for small services, FastAPI for JSON APIs. What to learn, in what order.

Web dev with Python means writing the server side. Python receives an HTTP request, talks to a database, and hands back either a rendered HTML page or a JSON payload. The browser never runs a line of it.

That boundary decides almost everything else on your learning list: which framework you open tonight, which server you run in production, and how much HTML, CSS and JavaScript you still have to know. Below is the order to learn it in, and roughly how many evenings each stage costs.

The short version: Python runs on the server. Pick Django for a site with logins and an admin, Flask for a small service you assemble yourself, FastAPI for a JSON API. Three days gets a running app, one week gets it deployed, one month gets it tested and on PostgreSQL.

What “Web Dev With Python” Actually Means

Python does three jobs on the server, and every framework is some arrangement of them.

  1. Render HTML. A request comes in, Python pulls data and fills a template, and the browser gets a finished page. This is how Django’s admin, most content sites and most internal tools work.
  2. Serve JSON. A request comes in, Python returns data with no markup. Something else renders it: a React app, a mobile app, another service, a model pipeline.
  3. Run work outside the request. Sending email, resizing an image, retraining something nightly. The user’s request returns immediately and the work happens elsewhere.

Everything the user actually sees, the browser does. HTML structures the page, CSS styles it, JavaScript makes it move. Python has no access to any of that once the response has been sent.

There is one asterisk worth naming so you can stop wondering about it. Pyodide is a port of CPython to WebAssembly, a Python distribution that runs in the browser and in Node.js and can load packages like NumPy and pandas. PyScript builds on it so you can put Python in a script tag on a page. Both are real and both work. Neither is what “Python web developer” means on a job posting, and neither replaces JavaScript for ordinary interface work. Treat them as a way to ship a notebook-style tool to people who cannot install anything, not as a career path.

If you are still shaky on functions, classes and imports, the frameworks below will feel like magic rather than code. Fix that first with the Python roadmap; web frameworks assume the language, they do not teach it.

The Request, Start to Finish

Here is the path a single page view takes. Every confusing piece of Python web tooling sits somewhere on this line.

browser
   │  HTTPS

reverse proxy ..... nginx, Caddy .......... TLS, static files


app server ........ Gunicorn, Uvicorn

═══╪═══ WSGI or ASGI: the boundary that decides which server you install


framework ......... Django, Flask, FastAPI
   │                router → middleware → view → template or JSON

ORM ............... SQL → database

Step by step:

  1. The browser resolves your domain and opens a TLS connection.
  2. A reverse proxy (nginx, Caddy, or whatever your host runs in front of you) terminates TLS and usually serves your static files directly.
  3. It forwards the request to an application server: Gunicorn, Uvicorn, or your platform’s equivalent.
  4. The application server calls your framework through a standard interface.
  5. The framework’s router matches the URL to a view function.
  6. Middleware runs on the way in: sessions, authentication, CSRF, security headers.
  7. Your view runs. It reads parameters, calls the ORM, and the ORM emits SQL.
  8. The database answers.
  9. The view renders a template or serialises a JSON response.
  10. Middleware runs on the way out, the response goes back through the proxy, and the browser paints it.

Steps 3 and 4 are where WSGI and ASGI live, and they are worth ten minutes of your attention because they decide which server you install.

WSGI, the Web Server Gateway Interface, is specified in PEP 3333. Your application is a single synchronous callable that takes an environ dictionary and a start_response callable and returns an iterable of bytestrings. One request in, one response out, blocking the whole way. Flask is a WSGI framework; Gunicorn is a pre-fork WSGI HTTP server for UNIX.

ASGI, the Asynchronous Server Gateway Interface, describes itself as “a spiritual successor to WSGI” and is a superset of it. Your application is a single asynchronous callable that takes scope, receive and send. Because receive and send are separate channels rather than one return value, a connection can stay open and messages can flow both ways, which is what makes WebSockets and long-lived connections possible. FastAPI is ASGI-native; Uvicorn is an ASGI server supporting HTTP/1.1 and WebSockets.

🔑 REMEMBER —

The framework’s built-in server is for you, not for users. Django’s own docs say of runserver: “DO NOT USE THIS SERVER IN A PRODUCTION SETTING. This lightweight development server has not gone through security audits or performance tests, hence is unsuitable for production.” That single sentence is the answer to “why do I need Gunicorn if Flask already runs?”

Django, Flask or FastAPI: One Rule for Choosing

Forget big project versus small project. The split does not predict which framework fits, because size is not what the three differ on. Choose on the shape of what you are building.

  • Shape 1: a site with logged-in users, forms and an admin back office. Someone signs in, fills things in, and someone else moderates it. → Django.
  • Shape 2: a small service, or an app you want to assemble yourself piece by piece. A webhook receiver, an internal dashboard, a thing where you want to choose every component. → Flask.
  • Shape 3: a JSON API consumed by something else. A separate frontend, a mobile app, another service, a model you are putting behind an endpoint. → FastAPI.

All three frameworks can build all three shapes. The rule is a default, not a law, and its job is to stop you spending your first week comparing instead of building.

Django 6.0Flask 3.1FastAPI 0.141
Default shape1: site with users and an admin2: small service, assembled by you3: JSON API
In the boxORM, migrations, admin, auth, forms, templates, i18n (translations), background tasks, CSP (Content Security Policy, an XSS defence)routing, Jinja templates, dev server, CLIvalidation from type hints, OpenAPI docs, dependency injection
Built onDjango’s own componentsWerkzeug, Jinja, ClickStarlette, Pydantic
Server interfaceWSGI and ASGIWSGIASGI
Minimum Python3.123.93.10
Version line6.0, stable, LTS cadence3.1, stablestill 0.x

Three honest caveats, because the marketing pages omit each of them.

FastAPI leads the usage surveys and is still pre-1.0. In the eighth annual Python Developers Survey run by the PSF and JetBrains (30,000+ responses collected in October and November 2024), FastAPI was used by 38% of respondents, Django by 35% and Flask by 34%, with FastAPI up 9 points year on year. The 2025 Stack Overflow Developer Survey put FastAPI at 14.8% of all respondents, Flask at 14.4% and Django at 12.6%, with FastAPI leading at 15.1% among professional developers. It is also still on a 0.x version number, and it ships no ORM, no migrations, no admin and no user model. You supply those.

Django ships the most and asks for a newer Python. Django 6.0, released 3 December 2025, supports Python 3.12, 3.13 and 3.14 only. If you are pinned to 3.10 or 3.11, you need the Django 5.2.x series, which is the last to support them. Django 5.2 is an LTS: its mainstream support ended on 3 December 2025 and its security and data-loss fixes run to April 2028.

Flask’s smallness is a bill, not only a virtue. No ORM means SQLAlchemy. No migrations means Alembic. No auth means Flask-Login or equivalent. Those are good libraries, and choosing and wiring them is real work you do before you write a feature.

What Python Will Not Do For You

No framework removes this list. Budget for it.

  • HTML and CSS. Enough to build a form, a table and a layout that does not embarrass you. A day or two, not a course.
  • Enough JavaScript to send a fetch call, read the response, and update part of the page. That is a genuinely small amount of JavaScript, and it is different from learning React.
  • SQL. An ORM writes queries for you until the day it writes a bad one. You need to read SELECT, JOIN and WHERE and know what an index is for.
  • HTTP semantics. Status codes, headers, cookies, sessions, CORS. Most “why does my API fail from the browser but work in curl” questions are one CORS header.
  • Git, and one deployment target you know end to end. A managed platform (Render, Railway, Fly.io) if you want the URL tonight; a VPS you configure yourself, with nginx, systemd and Let’s Encrypt, if you want to know what the platform was doing for you. Learn one properly before you learn a second.

There is a real escape hatch if you do not want a JavaScript framework. htmx exposes AJAX and CSS transitions as HTML attributes, with WebSockets and server-sent events supported via separate extensions since 2.0; it is dependency-free and around 16 KB minified and gzipped. You return HTML fragments from Python and htmx swaps them into the page. Django 6.0 pairs with this well because template partials are now in core: define a fragment with {% partialdef %}, render it with {% partial %}, and address it from a view as template_name#partial_name. Server-rendered interactivity, no build step.

Reach for a real frontend framework when the browser genuinely owns state: an editor, a canvas, an offline-capable app, or a native mobile client that has to share your API. That is shape 3, and it is the point at which the split pays for itself. If you are weighing which side of that line to specialise on, the JavaScript vs Python comparison is the longer version of that argument.

Async, and When It Actually Helps

Async is a common wrong reason to pick a framework. It buys concurrency on IO waits, not speed.

If your view spends 200 ms waiting on a database, an HTTP call or a disk read, async lets one process handle other requests during that wait. If your view spends 200 ms doing arithmetic, async does nothing at all, because nothing is waiting.

sync: B waits for A to finishAA waits on the DBAB is queuedBboth doneasync: B runs in A's waitAA waits on the DBABboth doneIf the 200 ms is arithmetic, notwaiting, async saves nothing.
Async fills A's waiting time with B's work. Neither request runs any faster.

Flask’s own documentation is unusually blunt about this. It states that “Async is not inherently faster than sync code”, that with async views “each request still ties up one worker” so the number of concurrent requests the app can handle is unchanged, and that “Flask’s async support is less performant than async-first frameworks”. Async views also need the extra: pip install flask[async].

Django gives you async views and an async ORM interface. Since Django 4.1, queryset methods have a-prefixed variants such as aget() and acreate(), and you can iterate a queryset with async for; model instances gained asave(), adelete() and arefresh_from_db() in 4.2.

async def author_detail(request, pk):
    author = await Author.objects.aget(pk=pk)
    latest = await author.books.afirst()
    return render(request, "authors/detail.html", {"author": author, "book": latest})

Two limits survive into Django 6.0. Transactions still do not work in async mode, so anything transactional should be a synchronous function called via sync_to_async(). And async views served under a WSGI server run in a one-off event loop per request, which buys none of the concurrency benefit; the payoff only arrives under ASGI.

FastAPI starts on the other side of that line, since it is built on Starlette and is ASGI-native.

⚠️ GOTCHA —

Pick async when you have many concurrent slow IO calls, WebSockets, or long-lived connections. Otherwise pick on project shape and let the framework’s default mode be the default.

The Toolchain You Will Actually Type

In order, on a fresh machine:

python3 -m venv .venv
source .venv/bin/activate
pip install django
django-admin startproject mysite
cd mysite
python manage.py migrate
python manage.py runserver

Python 3.14.6 is the current stable release, published 10 June 2026; 3.14 is supported until October 2030 and 3.13 until October 2029. Either is a safe floor for a new project. The virtual environment is not optional, and the mechanics of venv and pip are worth twenty minutes up front: virtual environments and pip, explained.

For FastAPI, the documented install pulls in the server and the CLI together:

pip install "fastapi[standard]"
fastapi dev main.py

Use SQLite in development, since it is a file and needs no setup, and PostgreSQL in production. Run migrations rather than editing tables by hand. Keep secrets in environment variables, never in the settings file you commit.

For production, put a real server in front of your app:

gunicorn mysite.wsgi:application --workers 3   # WSGI app
gunicorn -k asgi main:app                      # ASGI app, Gunicorn 25.1+
uvicorn main:app --host 0.0.0.0 --port 8000    # ASGI, standalone

Gunicorn 24.0, released 23 January 2026, added a native asyncio ASGI worker invoked as -k asgi, with HTTP/1.1 keepalive, WebSockets, the lifespan protocol and optional uvloop. It shipped there as beta and was promoted to stable in 25.1.0 on 13 February 2026, so production wants 25.1 or later; 26.0.0, from 5 May 2026, is the current release and adds an ASGI framework compatibility suite. One process manager now covers both worlds, which removes a step of the old FastAPI deployment folklore.

Common mistakes

  • Shipping the dev server. runserver, flask run and fastapi dev are development tools. Production gets Gunicorn or Uvicorn behind a proxy.
  • Skipping the virtual environment, then installing everything globally and wondering why two projects conflict.
  • Committing the secret key or database URL. Environment variables from day one, before the repo is public.
  • Learning the ORM instead of SQL. You will hit a slow query, and the fix lives in the SQL the ORM generated.
  • Picking a framework on benchmarks. Your first bottleneck is a missing index, not the router.
  • Reaching for async because it sounds faster. Re-read the section above.
  • Starting a new Django project on an old Python. Django 6.0 needs 3.12 or newer; on 3.10 or 3.11 you are on the 5.2 LTS series whether you meant to be or not.

Three Days, One Week, One Month: What Each Buys You

Assume evenings, not full days, and assume you can already write Python.

Three days: a running app on your own machine. Day 1: install, virtual environment, startproject, one URL that returns “hello”. Day 2: a second route, one template with real data in it, static files loading. Day 3: one HTML form that saves a row to SQLite and redirects. What it does not get you: no auth, no deployment, no tests, nothing anyone else can visit.

One week: a URL you can send to someone. Days 4 and 5: models and migrations, so your data has a shape you can change safely. Understanding that models are classes helps here, and classes, __init__ and self are the prerequisite if that part feels opaque. Day 6: login, logout and one page only a signed-in user can see. Day 7: environment variables for secrets, a real server behind a proxy, a live URL — a managed platform (Render, Railway, Fly.io) is the fastest way to have one by the end of the evening. What it does not get you: no tests, no background work, no CI, and you will not yet know what breaks under load.

One month: something you would put on a CV. Week 3: an API layer. On Django that is Django REST Framework, the most-named favourite third-party package at 49% in the Django Developers Survey 2025; DRF 3.17.1, released 24 March 2026, supports Django 4.2 through 6.0 on Python 3.10+. On FastAPI the OpenAPI schema and interactive docs come with the framework. Week 4: tests you actually run, PostgreSQL instead of SQLite, and background work moved out of the request. Django 6.0 puts a Tasks framework in core: decorate a function with @task from django.tasks and call .enqueue(). The two built-in backends are aimed at development and testing: ImmediateBackend runs the task inline rather than in the background, and DummyBackend does not run it at all, just stores the result. Django ships the interface, not a worker, so production needs a third-party backend that supplies the queue and a process to drain it. If decorators are still a mystery, learn that mechanism first; every one of these frameworks leans on it. Then build a second project without a tutorial. That one is what proves the first. What it does not get you: production operations, real security review, or scale.

Those three timeframes map onto our Python tiers, which cover the language rather than any framework: Python in Three Days if the syntax is the shaky part before you start, Python in One Week as cram-ready notes to keep open beside the docs, and Python in One Month for the full beginner path. If you are working toward interviews rather than a side project, Python in Three Months is the job-ready depth.

Where to Start Based on Where You Are Now

Absolute beginner. Build shape 1, because it teaches models, forms, auth and templates in one pass. Django, official tutorial, tonight. Do not comparison-shop.

JavaScript developer adding a Python backend. You already own the frontend, so you are in shape 3. FastAPI, and your type hints do double duty as validation and as OpenAPI docs.

Working developer with an interview in two weeks. Let the job posting choose. If it names a framework, build the smallest real thing in it. If it names none, Django plus DRF covers the widest ground, and the language questions are in Python interview questions.

Senior engineer evaluating the stack. The deciding facts are support windows and what you would otherwise assemble. Django 6.0’s own mainstream support ends in August 2026, when 6.1 ships, and its extended support ends April 2027. Django 5.2’s security support runs to April 2028 and the next LTS, 6.2, is scheduled for April 2027, though 75% of Django survey respondents start new projects on the latest stable release rather than the LTS. FastAPI’s pre-1.0 version number and absent ORM, migrations and admin are the trade you are making for the API ergonomics.

Whichever one you pick, the first commit is a URL that returns text. Everything above is what you add after it works.

Frequently asked questions

Can you do web development with Python?

Yes, on the server side. Python receives the HTTP request, queries the database, and returns an HTML page or a JSON response. The browser still runs HTML, CSS and JavaScript, so Python handles everything up to the moment the response leaves your server.

Should I learn Django, Flask or FastAPI first?

Choose by the shape of what you are building. A site with logged-in users, forms and an admin back office points to Django; a small service you want to assemble piece by piece points to Flask; a JSON API consumed by a separate frontend or a model points to FastAPI. All three can do all three, so the default just saves you a week of deliberating.

Do I still need JavaScript for Python web development?

You need enough to handle a fetch call, read a form and update part of a page. You can avoid a full JavaScript framework by returning HTML fragments from the server and swapping them in with htmx, or by using Django 6.0 template partials. A framework becomes worth it when the browser holds real state of its own.

How long does it take to build a web app with Python?

Three focused days gets a running app with routes, a template and a form on SQLite on your own machine. A week adds models, migrations, login and a deployed URL. A month adds an API layer, tests, background work and PostgreSQL, plus a second project you build without a tutorial.

Is FastAPI production-ready if it is still version 0.x?

It is widely used in production and led both the 2025 Stack Overflow survey and the eighth Python Developers Survey among web frameworks, but the 0.x version number is a real signal: minor releases can carry breaking changes, so pin your version. It also ships no ORM, no migrations and no admin, which you supply yourself.