layoutEngineering

Django

Batteries-included CRUD: where Django wins, ORM discipline and the N+1 trap, safe migrations, async limits.

1 item

Links1

01NotesNote

Where Django still wins

When you want batteries included: admin, auth, migrations, ORM, forms, and a mature ecosystem out of the box. For CRUD-heavy products with a real data model and an internal admin need, Django + DRF gets you to production faster than assembling the equivalent from FastAPI parts. This is why vorrei.io's core sits on Django.

ORM discipline — the N+1 problem

The single biggest Django performance trap. Accessing a related object inside a loop fires one query per iteration.

# BAD — 1 query for orders + N queries for each order.client
for order in Order.objects.all():
    print(order.client.name)

# GOOD — 2 queries total
for order in Order.objects.select_related("client"):
    print(order.client.name)
  • select_related → SQL JOIN, for forward FK / one-to-one.
  • prefetch_related → separate query + Python join, for reverse FK / many-to-many.
  • Catch these in development with django-debug-toolbar or by asserting query counts in tests (assertNumQueries).

Query efficiency

  • .only() / .defer() to limit columns on wide tables.
  • .values() / .values_list() when you don't need model instances.
  • bulk_create / bulk_update instead of per-row saves.
  • QuerySet.iterator() for large result sets to avoid loading everything into memory.
  • Push aggregation into the DB with annotate() + Sum/Count rather than computing in Python.

Migrations

  • Keep them small and reviewed. A migration that adds a non-null column without a default locks the table on large datasets — add the column nullable, backfill, then constrain.
  • For zero-downtime, separate schema changes from data backfills, and run backfills in batches.

Async caveats

  • Django's async support is real but partial. The ORM is not fully async; calls inside async views need sync_to_async, and you don't get true async DB I/O the way you do with SQLAlchemy async.
  • Rule of thumb: if a service is genuinely async-heavy (lots of concurrent outbound I/O), FastAPI fits better. If it's CRUD + admin, stay sync Django and scale with more workers.