Hamidreza
Hamidreza

Reputation: 1677

how to deal with python decorators in a class hierarchy?

I'm developing a Django project using DRF. I also have used drf-yasg for documentation purposes.

Long story short: I'm using class-based views and I have some APIs which are so similar and I decided to make a super-class and implement common parts of the APIs in it! For being more clear:

class MySuperApiView(APIView):
    permission_classes = [<some permission classes>]

    def uncommon(self):
        pass  # to be override in subclasses

    @swagger_auto_schema(request_body=request_body, responses=api_responses)
    def post(self, *args, **kwargs):
        # do some common stuff here
        self.uncommon()
        # do some other common stuff here

And I just override uncommon method in child-classes:

class SomeCustomApi(MySuperApiView):
    def uncommon(self):
        # do specific things here

It works fine but I have a little problem: Every Api have its own api_responses which is initialized in the swagger_auto_schema decorator in super-class! And it's not possible to change it!

What do you recommend for such a situation? I really want to do OOP and observe DRY principle.

Upvotes: 2

Views: 800

Answers (1)

Hamidreza
Hamidreza

Reputation: 1677

I finally found the best way to do such a thing in Django! (So yes, I don't know how to deal with such a problem in other frameworks or languages!) I moved swagger_auto_schema decorator to child-class using a class decorator named method_decorator. So first of all I had to import this method:

from django.utils.decorators import method_decorator

And then I changed super-class and child-class like this:

class MySuperApiView(APIView):
    permission_classes = [<some permission classes>]

    def uncommon(self):
        pass  # to be override in subclasses

    # <I removed decorator from here!>
    def post(self, *args, **kwargs):
        # do some common stuff here
        self.uncommon()
        # do some other common stuff here
api_responses =  # responses which belong to "SomeCustomApi"

@method_decorator(name='post',
                  decorator=swagger_auto_schema(request_body=request_body,
                                                responses=api_responses))
class SomeCustomApi(MySuperApiView):
    def uncommon(self):
        # do specific things here

It works totaly fine :) however I prefer a solution in which I don't have to repeat the decorator and instead, just initialize the responses parameter. If you face such a problem in other languages and you have the answer for another language, please post your answer.

Upvotes: 2

Related Questions