Multitenancy¶
Assumptions¶
The following settings are required:
TOWEL_MT_CLIENT_MODEL
: The tenant model, e.g.clients.Client
.TOWEL_MT_ACCESS_MODEL
: The model linking a Django user with a client, must have the following fields:user
: Foreign key toauth.User
.access
: An integer describing the access level of the given user. Higher numbers mean higher access. You have to define those numbers yourself.- The lowercased class name of the client model above as a foreign key
to the client model. If your client model is named
Customer
, the name of this foreign key must becustomer
.
All model managers have a
for_access()
method with a single argument, an instance of the access model, which returns a queryset containing only the objects the current user is allowed to see. The access model should be available asrequest.access
, which means that you are free to put anything there which can be understood by thefor_access()
methods. Therequest.access
attribute is made available by thetowel.mt.middleware.LazyAccessMiddleware
middleware.towel.mt.modelview.ModelView
automatically fills in acreated_by
foreign key pointing toauth.User
if it exists.The form classes in
towel.mt.forms
, those beingModelForm
,Form
andSearchForm
all require the request (the two former on initialization, the latter onpost_init
). Model choice fields are postprocessed to only contain values from the current tenant. This does not work if you customize thechoices
field at the same time as setting thequeryset
. If you do that you’re on your own.The model authentication backend
towel.mt.auth.ModelBackend
also allows email addresses as username. It preloads the access and client model and assigns it torequest.user
if possible. This is purely a convenience – you are not required to use the backend.
Forms¶
These three form subclasses will automatically add limitation by tenant
to all form fields with a queryset
attribute.
Warning
If you customized the dropdown using choices
you have to limit the
choices by the current tenant yourself.
Middleware for a lazy request.access
attribute¶
-
class
towel.mt.middleware.
LazyAccessMiddleware
This middleware (or something equivalent providing a
request.access
attribute must be put inMIDDLEWARE_CLASSES
to use the helpers intowel.mt
.
Models for multitenant Django projects¶
The models for towel.mt
have to be provided by the project where
towel.mt
is used, that’s why this file is empty.
The simplest models might look like that:
from django.contrib.auth.models import User
from django.db import models
class Client(models.Model):
name = models.CharField(max_length=100)
class Access(models.Model):
EMPLOYEE = 10
MANAGEMENT = 20
ACCESS_CHOICES = (
(EMPLOYEE, 'employee'),
(MANAGEMENT, 'management'),
)
client = models.ForeignKey(Client)
user = models.OneToOneField(User)
access = models.SmallIntegerField(choices=ACCESS_CHOICES)
API methods can be protected as follows:
from towel.api import API
from towel.api.decorators import http_basic_auth
from towel.mt.api import Resource, api_access
# Require a valid login and an associated Access model:
api_v1 = API('v1', decorators=[
csrf_exempt,
http_basic_auth,
api_access(Access.EMPLOYEE),
])
api_v1.register(SomeModel,
view_class=Resource,
)
Other views:
from towel.mt import AccessDecorator
# Do this once somewhere in your project
access = AccessDecorator()
@access(Access.MANAGEMENT)
def management_only_view(request):
# ...