Skip to content
PRS India

Python 3.12 · Django · FastAPI · Celery

Python Development

The language for the work behind the website: data, ML inference, automation and APIs that handle many requests. We do Python development on Django, FastAPI and Flask, typed with mypy, packaged so it runs the same everywhere, and honest about where async helps and where it hurts.

Last updated

  • Django, FastAPI or Flask — chosen per service, with reasons
  • Async where it helps, process pools where it does not
  • Typed with mypy, packaged in containers, same result every time
  • The work around a model, not just the model
Python Development
Why Python

The language for the work behind the web layer.

The reason to choose Python is rarely the web page. It is everything behind it: data pipelines, machine-learning inference, document and image processing, scientific computing, automation, and APIs whose real job is to sit in front of a model. For this kind of problem, Python has a library for almost everything, and many people already know it. It is also a really good web backend. Django can run a full product with payments and orders, and FastAPI can run an API with many requests. You just need to pick the framework the problem really needs. Most of our Python development is one of two kinds: a Django product with a real admin, or a small FastAPI service in front of a model or a data job. We build both. We are also open about the one case where we would pick a different language.

Talk to a Python engineer
mypy
Types in CI

Type hints checked on every pull request. A reviewer can understand how Python code behaves, so there are no 2am surprises.

async
Where it earns it

FastAPI async for concurrent I/O; process pools for CPU-bound work. We never block the event loop and call it fast.

1
Reproducible runtime

A lockfile and a container, so the app behaves identically from a laptop to production. No "works on my machine".

pytest
Against real deps

Tests that exercise the database and the queue, not a wall of mocks agreeing with themselves.

How we actually build it

Python is the language we pick when the hard part of the problem is not the website but the work behind it: data pipelines, machine-learning inference, document and image processing, scientific computation, automation and scraping, or an API whose real job is to sit in front of a model. It is also a perfectly good choice for a straight web backend. The skill is knowing which framework the problem is actually asking for, because "Python development" covers three very different tools.

Django, FastAPI or Flask — a decision with consequences

Django is the choice with everything included: an ORM, migrations, an admin, login and a mature set of tools. It is ideal for a content-heavy product or one with many orders, where the team gains from strong rules and a ready-made back office. FastAPI is what we use for fast, async-first APIs that handle many requests, and for anything serving a model. It has typed request and response schemas from Pydantic, automatic OpenAPI docs, and async that holds up when many things happen at once. Flask is still the right answer for a small service with a narrow job that needs no more framework than necessary. We pick per service, sometimes running Django for the product and FastAPI for the inference tier in the same system, and we write down why.

Async is a tool, not a religion

FastAPI and modern Python make async easy to write. This tempts teams to make everything async and then block the event loop with a synchronous database driver or a heavy CPU call. That is the worst of both worlds. We use async where the work is truly I/O-bound and happens at the same time. We keep the CPU-heavy work in a process pool or a separate worker. We never mix a blocking library into an async path without noticing. Getting this line wrong is the most common reason a "fast framework" mysteriously stalls under load. It is one of the things we are most often called in to fix.

Packaging, environments and the reproducibility problem

Python's old weakness is that "it works on my machine" is a real danger. We pin the versions of all packages with a lockfile, use a modern toolchain such as uv or Poetry, and ship in containers so the setup is the same from a laptop to production. Type hints and mypy in CI turn Python's flexibility from a risk into something a reviewer can understand. Tests run under pytest against real dependencies, not a wall of mocks. None of this is unusual. All of it is the difference between a Python service you can keep up and a script that has quietly become something everyone depends on.

When Python is fronting a model

A large share of our Python development sits between a product and a machine-learning model, whether that is a classic model you trained, an open-source model you host yourself, or a hosted LLM you call. The work that matters there is rarely the model. It is grouping and queuing requests so a slow call cannot block a request, caching a lot, handling timeouts and backups so a provider outage slows things gently and does not take the product down, and keeping a clean line so the model can be swapped without touching the application. Celery or a task queue carries the heavy work. FastAPI serves the thin, fast front.

The honest part

When Python is the right call — and when it is not.

  Choose Python Choose something else
Data, ML or scientific workload Yes, by a wide margin. No other language has as many tools for data and ML. Nothing we would suggest over it for this kind of problem.
API in front of a model FastAPI, async, typed schemas, and a task queue for the heavy work. This is exactly what it is good at. Pick something else only if the rest of your platform already uses another stack.
Content-heavy transactional web product Django is excellent. Admin, ORM, login and migrations come ready to use. Laravel is an equally strong answer if your team works in PHP. Pick by team, not by trend.
Sustained CPU-bound work in the request Only if the heavy calculation is moved into NumPy, a compiled extension or a separate worker. Go or Rust for the busiest part if the calculation really dominates. Let Python manage it.
100k concurrent WebSocket connections Possible with an async server, but not where Python is best. Go or Node for the socket part. Keep Python for the data and model work behind it.
Team has no Python and a tight deadline Fine for a service that stands alone. It is quick to learn. Do not force a whole product into a stack you do not know when time is short. Build in what your team can debug.
What we build

Python work we take on.

FastAPI services & APIs

APIs built async-first that handle many requests, with typed Pydantic schemas and generated OpenAPI docs. Often the fast front in front of a model or a data store.

Django products

Content-heavy web apps and apps with many orders, with the admin, ORM, login and migrations that get a real product live quickly.

Data pipelines & ETL

Taking in data, changing it and running scheduled jobs with pandas and a task queue. Built so you can see what happens and run it again, not a cron job nobody trusts.

ML inference services

The work around a model: grouping, queuing, caching, a safe backup plan and a model you can swap. It works for models you host yourself or a hosted LLM.

Automation & integration

Scraping, document and image processing, and small services that connect systems that were never meant to talk. We turn weak scripts into well-kept software.

Python rescue & hardening

A script everyone depends on, or an async service that stalls, gets types, tests and repeatable packaging. We find and fix whatever blocks the event loop.

Characteristics

What a Python service gets you, with the caveats.

  • An unmatched library ecosystem

    For data, ML, scientific computing, automation and connecting systems, the package you need almost certainly exists and is mature. This is Python's biggest advantage.

  • Strong concurrent I/O with async

    FastAPI on an async server handles many users at once when the work is I/O-bound, as long as nothing blocking sneaks onto the event loop.

  • Type safety when you insist on it

    Type hints and mypy in CI make a flexible language easy to review. We treat a public interface with no types as a fault, not a choice.

  • Heavy work off the request path

    Celery or a task queue carries inference, ETL and long jobs, with retries and a place for failed jobs, so the API front stays thin and fast.

  • Reproducible everywhere

    A lockfile and a container remove "works on my machine" completely. The setup is the same from a developer laptop to production.

  • Honest about CPU limits

    Long, heavy CPU work inside the same process is where Python struggles. We keep it apart or use the right tool for that part. We do not pretend the limit is not there.

How we build

From a fragile script to a service you can trust.

The path we take whether the work is a new API, a data pipeline or a feature that uses a model.

  1. 01

    Shape the workload

    Week 1

    We separate I/O-bound work from CPU-bound work, the request path from the background work, and the data side from the website. The framework choice (Django, FastAPI or Flask) comes from this, not from habit.

  2. 02

    Set the foundation

    Week 1–2

    A fixed toolchain, containers, type hints with mypy, and pytest connected to CI before feature work starts. The plain groundwork that decides whether the project is easy to keep up in month six.

  3. 03

    Build the thin edge and the heavy tier

    Weeks 2–8

    A fast, typed API at the front. The heavy work (inference, ETL, long jobs) goes on a task queue with retries and a place for failed jobs. The line between them is clear and can be swapped.

  4. 04

    Load, degrade and observe

    Weeks 8–10

    We test with many users at once, check that the async line holds, and make sure a slow outside system or a provider outage slows things gently. Clear logs, error tracking and speed dashboards go in here.

  5. 05

    Hand over

    Final week

    Run guides, a design note and a getting-started session so your team can run and extend it. Or we stay on a monthly plan with a set SLA response time.

The stack

What ships with a Python build from us.

Tools we pick when the choice is ours. We swap them when your platform already runs something else.

Django 5
FastAPI
Flask
Pydantic

Bring us the data problem, the model, or the async service that stalls.

Tell us what the work behind your website really is, and where it hurts. A senior engineer replies within one business day with scope, risk and a price, not a brochure.

FAQ

The questions you were going to ask on the call.

Django when the product is content-heavy or has many orders, and needs an ORM, migrations, an admin and login ready to use. It gets a full web app live fast. FastAPI when the job is an async-first API that handles many requests, or anything serving a model, with typed Pydantic schemas and automatic OpenAPI docs. Flask for a small service with a narrow job that needs no more framework than necessary. These are not rivals. They are tools for different jobs, and we often run Django for the product and FastAPI for the inference part in the same system. We choose per service and write down the pros and cons.

For the great majority of I/O-bound APIs, yes. The request spends its time waiting on a database or a network call, not on the interpreter, so the language speed is rarely the problem. FastAPI with async handles many users at once well. Where raw calculation matters, we move it into NumPy, a compiled extension, or a separate worker rather than fighting the interpreter. Python really struggles with long CPU-heavy work in the request path. There we would keep that work apart or use a different tool for that part, and tell you plainly.

Async makes Python good at many things at once: many requests, each waiting on something outside. It does nothing for CPU-heavy work. Worse, one blocking call on an async path stalls the whole event loop. This is how a "fast framework" ends up mysteriously slow under load. We use async where the work is truly I/O-bound. We keep CPU-heavy work in a process pool or a separate worker. We never let a blocking driver slip into an async route unnoticed. Keeping this line clear is one of the things we are most often called in to repair.

That is most of our Python work. The model is rarely the hard part, whether you trained it, host an open-source one yourself, or call a hosted LLM. The hard part is the work around it: grouping and queuing requests so a slow call cannot block a request, caching a lot, handling timeouts and backups so a provider outage slows things gently and does not take the product down, and keeping a clean line so the model can be swapped without touching the application. Celery or a task queue carries the heavy work; a thin FastAPI front serves the fast path.

By treating it like real software from the first commit. Packages fixed with a lockfile and a modern toolchain such as uv or Poetry. The app shipped in containers so the setup is the same everywhere. Type hints with mypy in CI so a reviewer can really understand the code. And pytest against real dependencies, not a wall of mocks. Python's flexibility is a risk only when it has no rules. With types, tests and repeatable packaging, it becomes a strength and not a source of 2am surprises.

A focused API or automation service usually takes 6 to 10 weeks and starts from around ₹7,50,000. A full Django product with an admin, login, payments and connections to other systems takes 14 to 24 weeks and starts around ₹18,00,000. A data or ML service is planned after a short discovery, because the cost depends on data quality, amount of data and the inference work, not the website. As always, connections to other systems and the state of your data change the price. A paid discovery exists to find this out before we quote.

Let's talk python development

Bring us the hard version of the problem.

A senior engineer reads every enquiry. You'll get a real answer — scope, risk and a number — within one business day.