Think Build Implement Repeat
London, UK +44 7367 067226
WhatsApp FOLLOW f in X
  1. Home
  2. Blog
  3. Making Sure People See Only What They Should
Python & Django

Making Sure People See Only What They Should

Permissions and multi-tenant data separation in Django: record-level access filtered at the query, enforced centrally and tested with two accounts.

Updated 2 min readBy SpiderHunts Technologies

Free estimateNo obligation

Get a free estimate

Tell us what you need. A senior engineer reads every enquiry.

Takes under a minute. We never share your details.

  • Free consultation
  • No commitment
  • NDA on request

Prefer to talk? Book a free 30-minute call →

Quick answer — TL;DR

Django's permissions cover the action; record-level access needs building. Filter every query by what the user may see, and test it with two accounts trying to reach each other's data.

Two different questions

  • May this user perform this action? Django's permissions answer this
  • May this user access this record? This needs building
The most common authorisation failure in business applications is checking the action but not the record. A user permitted to view orders viewing someone else's order.

Filter at the query

  1. Every list query filtered by what the user may see
  2. Every detail view checking ownership before rendering
  3. Never trusting an identifier in the URL to determine access
  4. The same rules applied to any API endpoints
  5. The same rules applied to exports and reports

Exports are the commonly forgotten one. A report that ignores the permission filter leaks everything the interface carefully restricted.

Multi-tenant separation

ApproachSuits
Tenant field on every model, filteredMost business applications
Separate schema per tenantStronger separation, more operational work
Separate database per tenantStrongest, most operational work

For most applications, a tenant field with enforced filtering is adequate — provided the filtering is genuinely enforced everywhere rather than remembered on each query.

Enforce it centrally

Relying on every developer to remember the filter on every query is how leaks happen. Enforce it in a base manager or a mixin so the safe path is the default.

Then any query that bypasses it is visible in review as an explicit exception rather than an omission.

Test it adversarially

  • Two accounts, deliberately trying to reach each other's records
  • Direct URL access with another user's identifiers
  • Exports and reports, not just screens
  • API endpoints, not just the web interface
  • After every significant change

FAQ

Frequently asked questions

The questions readers ask us after this guide.

Still have a question?

Ask us directly — a senior engineer will get back to you.

Ask about your project

Are Django's built-in permissions enough?

For action-level permissions, largely. Record-level access needs building on top.

How do we handle a user in several roles?

Groups with permissions, and the user in several groups. Record-level access needs its own logic.

What about the admin?

It respects action permissions and needs explicit work for record-level filtering. Restrict admin access rather than relying on it.

How do we test separation properly?

Automated tests that attempt cross-tenant access and assert they fail. Manual testing misses cases.

Keep reading

More on Python & Django

Python & Django

An API Other Systems Can Depend On

Designing a Python API service others can depend on: validation at the boundary, consistent errors and status codes, early versioning and documentation.

Python & Django

Moving and Transforming Data Reliably

Building data pipelines in Python that cope with malformed input: restartable stages, quarantining failures, reconciling counts and alerting on absence.

Start here

Building something with tenant or customer separation?

Enforce the filter centrally rather than per query. Happy to review how yours works.

  1. You tell us what you needTwo minutes on the form, or a message on WhatsApp.
  2. A senior engineer reviews itAnd comes back with questions, a realistic range and an honest view on fit.
  3. Free 30-minute scoping callWe talk through scope, options and a realistic estimate — with no obligation.
Free estimateNo obligation

Talk to someone who builds this

Send a short brief and we will come back with an honest view and a realistic range.

Takes under a minute. We never share your details.

  • Free consultation
  • No commitment
  • NDA on request

Prefer to talk? Book a free 30-minute call →