iToverDose/Software· 7 JULY 2026 · 12:02

Why a Python framework can replace two-thirds of your production libraries

Choosing Django saved me from adding ten dependencies—but revealed two real gaps. Here’s how to audit your stack like a senior engineer.

DEV Community4 min read0 Comments

A recent list claiming 12 libraries to turn a Python script into production software made me pause. As the maintainer of a self-hosted AWS drift detector, I reviewed each suggestion against my stack. The result? Eleven libraries crossed off the list—not because I’m minimalist, but because Django handled them before I wrote a single line of code.

The real insight isn’t in the count. It’s in recognizing that picking a framework is itself the most significant dependency decision you’ll make. Here’s how one choice reshaped my production stack—and where the framework still left room for improvement.

Ten libraries replaced by a single framework choice

Choosing Django isn’t about avoiding dependencies. It’s about inheriting solutions to problems you didn’t realize you’d solved. Here’s what disappeared when I adopted Django, and why adding a second library would have created more problems than it solved:

  • `click` → Django management commands

My CLI isn’t a separate framework; it’s Django’s built-in manage.py commands. Argument parsing, help text, type coercion, and command discovery all come for free. Introducing click would create a parallel CLI layer that needs its own documentation, testing, and maintenance.

  • `SQLAlchemy` → Django ORM + `psycopg2`

I work with PostgreSQL via dj-database-url, which lets me switch databases with a URL change. Adding SQLAlchemy would mean maintaining two ORMs, two migration systems, and two identity maps—inviting subtle bugs and doubling cognitive load.

  • `marshmallow` → Django forms + boundary normalization

Untrusted input enters through Django’s form and model validation layer. AWS scan results get normalized into a fixed structure at the edge. The validation exists; it’s just not a separate library.

  • `schedule`/`celery` → `django-apscheduler`

My periodic scans run via Django’s scheduler. Celery would require Redis and a distributed task queue—complexity I haven’t earned and would need to debug at 2 AM. I’ve already written about the risks of duplicate schedulers in Django apps.

  • `structlog` → Standard library logging

The original problem structlog solves is graduating from print statements in scripts. My codebase uses logging with getLogger(__name__)—a solved problem before structlog entered the picture.

  • `python-dotenv` → Docker Compose environment injection

In production, docker compose injects environment variables. I read them via os.getenv at the settings boundary. python-dotenv is useful for local development when not using containers, but it’s not a production dependency.

  • `tqdm` → Structured log lines

My scan jobs run on schedules or web requests, not in attended terminals. A progress bar has no audience; a timestamped log line does.

  • `Docker SDK` → Containerized deployment

SyncVey is a container (docker compose up). The SDK isn’t needed to drive Docker from Python; the container is the deployment unit.

  • `pytest` → Django’s test runner

Django’s built-in test framework handles unit, integration, and database tests out of the box. Adding pytest would require extra configuration and risk breaking Django’s assumptions.

  • `boto3` → Already handled by AWS SDK

Boto3’s built-in retry logic already retries AWS API calls. Adding it separately would duplicate that functionality.

These ten libraries didn’t vanish because I’m dogmatic. They vanished because Django answered their core use cases before I needed to import them.

The two real gaps the framework left behind

No framework is perfect. Even after inheriting ten solutions, two gaps remained. Auditing the list revealed them—and forced me to confront a stray print statement that had slipped through my logging conventions.

  • `tenacity` for non-AWS HTTP retries

Boto3 handles retries for AWS calls, but my two non-framework HTTP calls—a Slack webhook post and an EOL calendar fetch—use raw urllib with no retry logic. A transient network error on either call fails the operation. This is exactly the use case the list highlights, and Django doesn’t cover it because it’s not a web framework concern. I should add tenacity here.

  • `structlog` for structured logging

I’m using Python’s standard library logging, which works. But structured JSON logs would make scan jobs and attribution failures queryable instead of greppable. The list didn’t just suggest a library; it made me look at my logging practices. In the process, I found a print that had bypassed my own conventions.

The lesson isn’t that frameworks eliminate all dependencies. It’s that they redefine where your dependencies belong.

The framework paradox: when to choose, and when to avoid

Frameworks excel when your project’s shape matches their default assumptions. A self-hosted service with periodic tasks, a database, and a web interface? Django’s model-view-template architecture fits like a glove. A data-munging script with no persistence and no surface area? That’s a weekend project where click, tqdm, and python-dotenv are the right tools.

The mistake isn’t choosing a framework. It’s assuming the same list of libraries works for both scenarios. Pretending one set of defaults fits every problem is how you end up with two ORMs, two CLI tools, and two logging layers—each needing synchronization, testing, and maintenance.

Audit your stack like a senior engineer

Before you pip install your next dependency, ask three questions:

  1. Does my framework already solve this?
  • CLI tools → Check built-in management commands.
  • ORM needs → Check your framework’s database layer.
  • Configuration → Check environment variable handling.
  • Logging → Check your framework’s logging conventions.
  1. If I add this library, will I be maintaining two copies of the same thing?

Two ORMs. Two CLI frameworks. Two configuration layers. Each pair introduces synchronization overhead and subtle bugs.

  1. Where does my framework leave gaps?

For me, it was retries on non-framework HTTP calls and structured logging. For you, it might be async tasks, real-time features, or specialized data processing.

The leverage in production stacks isn’t in the number of libraries. It’s in the one choice that pre-answers ten questions—and the discipline to audit the two it leaves behind.

AI summary

Python projelerinizi üretime hazır hale getiren en iyi 12 kütüphane ve hangilerinin gerçekten ihtiyaç duyulduğunu anlamak için Django kullanıcılarının deneyimlerini keşfedin.

Comments

00
LEAVE A COMMENT
ID #SC4BQZ

0 / 1200 CHARACTERS

Human check

2 + 5 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.