ICVOSS DJANGO PACKAGE REGISTRY

The package index django-boundary Scope a service or task that already holds the tenant

Scope a service or task that already holds the tenant

Documentation

Goal

Run a service function or background task under a tenant you already have in hand (passed as an argument), so tenant-scoped queries inside it auto-filter, without hand-writing with TenantContext.using(...) everywhere, and without reaching for a bespoke manager.

Prerequisites

When to use this

This is the blessed idiom for the "I hold the tenant explicitly" case:

If you catch yourself re-implementing tenant filtering inline, use this instead.

Steps

  1. Decorate the function, naming the argument that holds the tenant:

```python from boundary.context import tenant_scoped

@tenant_scoped("merchant") def run_audit(merchant, since): # merchant is active in context for the whole call return AccountAudit.objects.filter(created__gte=since) # auto-scoped ```

  1. If your project renamed the tenant (via BOUNDARY_TENANT_FK_FIELD), the default argument name matches it, so you can omit the name:

python # BOUNDARY_TENANT_FK_FIELD = "merchant" @tenant_scoped() # resolves the "merchant" argument def run_audit(merchant, since): ...

  1. With a Celery task that is handed the tenant directly, place @tenant_scoped below @shared_task:

python @shared_task @tenant_scoped("merchant") def rebuild_index(merchant): ...

Verify it worked

@tenant_scoped("merchant")
def count(merchant):
    return Product.objects.count()

assert count(merchant_a) == count_for_a
assert count(merchant_b) == count_for_b
# context is restored afterwards
assert TenantContext.get() is None

Common pitfalls