How to Build a Multi-tenant application with Django Rest Framework! — Part II

Bala Venkatesh
2 min readApr 8, 2020

Before reading this blog, Please Check out my previous Part I blog because this blog continues from part 1.

As you see above image, Take a look at the tenant table which is the parent table for all the tables. The tenant table is playing a very important role in the multitenant applications.

Step 1:- Create a tenant Model in models.py file

class TenantModel(models.Model):
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
class Meta:
abstract = True

Step 2:- Now, we have to inherit TenantModel to add tenant_id in child tables. For instance, I have an AppointmentTiming table where I want tenant id so I have inherited the tenant model.

class AppointmentTiming(TenantModel):
“””
Model to store the AppointmentTiming
“””
morning = ArrayField(models.CharField(max_length=10, blank=True))
afternoon = ArrayField(models.CharField(max_length=10, blank=True))
evening = ArrayField(models.CharField(max_length=10, blank=True))
class Meta:
db_table = ‘appointment_timing’

Step 3:- Get tenant_id from the request. check part 1, we created AuthenticationMiddlewareTenant in Step 5 where we were set request.user and request.tenant values in parameters because every request will come through middleware so we need to verify the token and setting parameter values.

request.user = user
request.tenant = tenant

Step 4:- While we save new data to the tables we should set current tenant id values to the tenant_id column. I used self.request.user.tenant_id the parameter to get current teant_id for all requests.

class AppointmentTimingView(viewsets.ModelViewSet):pagination_class = None
queryset = AppointmentTiming.objects.all()
serializer_class = AppointmentTimingSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = (‘tenant’,)
http_method_names = [‘get’, ‘post’, ‘patch’]
def get_queryset(self):
return self.queryset.filter(tenant=self.request.user.tenant_id)
def create(self, request, *args, **kwargs):
serializer = PatientsSerializer(data=request.data)
if serializer.is_valid():
serializer.save(tenant_id=self.request.user.tenant_id)
return Response(serializer.data,status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=
status.HTTP_400_BAD_REQUEST)

Step 5:- Create a view for the AppointmentTiming model where we should override the get_queryset method to retrieve the data based on tenant_id. Check the AppointmentTimingView class for your reference.

class AppointmentTimingView(viewsets.ModelViewSet):
“””
retrieve:
Return a AppointmentTiming instance.
list:
Return all AppointmentTiming.
create:
Create a new AppointmentTiming.
partial_update:
Update one or more fields on an existing AppointmentTiming.
update:
Update a AppointmentTiming.
“””
pagination_class = None
queryset = AppointmentTiming.objects.all()
serializer_class = AppointmentTimingSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = (‘tenant’,)
http_method_names = [‘get’, ‘post’, ‘patch’]
def get_queryset(self):
return self.queryset.filter(tenant=self.request.user.tenant_id)

That’s it!! Now we can use our DRF application as a Multi-tenant application using the Data segregation model.

Note:- keep in mind that, whenever handling CRUD operation we should check tenant_id in that table because data breach problems may occur by showing irrelevant tenant data to your tenant application.

If you need any clarification, feel free to leave the text to me.

--

--

Bala Venkatesh

I have a passion for understanding technology at a fundamental level and Sharing ideas and code. * Aspire to Inspire before I expire*