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

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

Image for post
Image for post

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.

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

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store