r/django • • 19h ago

How much rollback infrastructure is reasonable for a small app?

1 Upvotes

Had one of those deployments recently where everything looked fine until I started clicking around and realized I'd broken something that had nothing to do with the change I made.

Nothing catastrophic and I fixed it pretty quickly, but it exposed how bad my rollback plan is.

For a small app or tiny team, what do you consider the sensible minimum here?

I don't want to build some elaborate deployment pipeline for a project with modest traffic, but rebuilding the previous commit while something is broken feels like a pretty dumb recovery strategy too.

Ideally I'd like deployments to keep known-good versions around so putting the previous one live is basically an immediate action, then I can figure out what I broke without rushing.

Curious how people handle this before the project is big enough to justify serious DevOps work.


r/django • • 4h ago

Incidents – OpenLayers

Thumbnail magula10.pythonanywhere.com
0 Upvotes

r/django • • 23h ago

Two DRF mistakes I fixed in a multi-tenant SaaS: per-view tenant filtering, and workers with CONN_MAX_AGE = 0

4 Upvotes

Sharing two concrete fixes from a Django REST + PostgreSQL build I am working on (a multi-tenant SaaS, one shared database, tenant column on the tenant-owned models). Posting in case it saves someone else the debugging time.

Mistake 1: filtering by tenant inside each view, by hand. Early on, individual views did things like Model.objects.filter(tenant=request.user.tenant) — until one list endpoint missed it and a detail view used a raw get_object_or_404 with only the PK. Nothing bad reached production, but code review caught how easy it would be to miss one. Fix: a single TenantScopedViewSet mixin that overrides get_queryset() and filters by the authenticated user's tenant, plus a matching manager-level check in tests. The rule in the codebase now is simple: if a view is not using the mixin, that is a bug to explain in review. Detail views get the same scoped queryset, so a cross-tenant PK returns 404 instead of leaking existence.

Mistake 2: ignoring connection settings for background work. Web requests were fine, but my background worker processed document jobs in a loop and, with CONN_MAX_AGE = 0, opened a fresh Postgres connection for every job. Under a batch of uploads that showed up as connection churn and avoidable latency. Setting a sane CONN_MAX_AGE for the worker (and making sure connections are closed cleanly where Django expects long-lived processes to handle it) removed most of that overhead.

Question for people running multi-tenant DRF on one database: do you enforce tenant scoping at the viewset/mixin layer like this, at a custom manager layer, or with Postgres row-level security? I picked the mixin + tests because it is explicit, but RLS looks stronger as a backstop.


r/django • • 4h ago

Incidents – OpenLayers

3 Upvotes