Kok Hoor Chew
Kok Hoor Chew

Reputation: 170

Generic ModelSerializer for Django REST Framework

In my ModelViewSet, I am trying to exclude my tenant field to prevent users from seeing the tenant id (from django-simple-multitenant). However, I am not able to develop a generic ModelSerializer because I am always required to define the model Meta in the ModelSerializer class. My source code that works (non-generic) is below. I would like to achieve either one of the options below:

  1. Serializer works by picking up actual class model without need to specify the model in Meta class of the serializer

  2. Set my Serializer in DEFAULT_MODEL_SERIALIZER_CLASS, and have it work (again without specifying the model in the Meta class of the serializer

It works well below, but when I assign the Serializer in DEFAULT_MODEL_SERIALIZER_CLASS, it does not seem to work.

class ExcludeTenantSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        exclude = ('tenant', )


class ProductViewSet(viewsets.ModelViewSet):
    model = Product
    ordering = ('id', )
    serializer_class = ExcludeTenantSerializer

    def get_queryset(self):
        tenant = get_current_tenant()
        if tenant:
            return self.model.objects.filter(tenant=tenant)
        else:
            return self.model.objects.none()

Upvotes: 4

Views: 2267

Answers (1)

Kok Hoor Chew
Kok Hoor Chew

Reputation: 170

I have found a way to do this. It is to dynamically create a class in the get_serializer_class function. To make this generic, I wrote a class that extends from ModelViewSet, and have all the multi-tenant aware classes that I will expose through Django REST Framework to subclass it.

class TenantViewSet(viewsets.ModelViewSet):
    def __init__(self, **kwargs):
        self.serializer_class = None
        super(TenantViewSet, self).__init__(**kwargs)

    def get_serializer_class(self):
        if self.serializer_class is not None:
            return self.serializer_class

        class ExcludeTenantSerializer(serializers.ModelSerializer):
            class Meta:
                model = self.model
                exclude = ('tenant', )

        self.serializer_class = ExcludeTenantSerializer
        return self.serializer_class

    def get_queryset(self):
        tenant = get_current_tenant()
        if tenant:
            return self.model.objects.filter(tenant=tenant)
        else:
            return self.model.objects.none()

Upvotes: 5

Related Questions