I'm developing a web application that will store multiple Organizations
, where each organization has its own users. An organization is identified by a domain
(CharField
), and users only see data pertaining to their own organization. For simplicity and performance reasons, I store the data of all organizations onto the same database instead of creating N databases/views.
What I want to implement is a simple way to restrict queries by the relevant domain
whenever I'm in the context of a user request.
What I tried
Filtering all querysets
Since each User belongs to an organization the first option that comes to mind is to use a queryset
defined this way:
queryset = MyModel.objects.all(domain=request.user.domain)
I can't use this solution because it forces the developer to filter all queries manually all around the web application. If someone forgets to properly filter querysets, users of an organization can see data of other organizations. It's error-prone.
Thread locals
Since I can find the user inside the request. another solution would be to expose the request through a middleware and automatically filter by domain using the domain of the user that will execute the request. For this purpose I found this question but opinion are quite divergent.
I still have to figure out exactly why using thread locals is a bad choice. I discussed this on Freenode / #django but no one expanded on the reasons to avoid it. I would like to better understand what are the pros & cons of this solution.
Model mixins
I would like to have a mixin (let's say a DomainModelMixin
) that sets two managers:
objects = DomainManager()
super_objects = models.Manager()
super_objects
is the default manager (unfiltered), and objects
is a custom manager that filters by domain and only provides data pertaining to the organization.
The problem is that at the model layer we don't have the request, and therefore we don't have the User and we don't know which domain
to restrict the queryset to. How can we pass the domain
to the manager?
The big question
How can we automatically filter objects.all()
in a way that is transparent and easy to use for developers? And what if we want use the same logic from a context that doesn't have a Request object (e.g. the interactive shell or tests)?