ritratt
ritratt

Reputation: 1858

How to inject an attribute or an object into a view in Django Rest Framework?

I am kinda new to Django Rest Framework.

I have a views.py that looks something like this:

class MyAPIView(APIView):
  """ My API """

  def get(self, request, path):
    """ Handles GET calls """

  def post(self, request, path):
    """ Handles POST calls """

And I have a util class in my package like so:

class MyUtilClass: """ Helps out with stuff """

def some_method(self, path): print('I will now do things to the path: ', path)

Now, I would like to inject an instance of some other class that does some task that it's supposed to into my view. Something like this:

class MyAPIView(APIView):
  """ My API """

  _some_util_instance = None # How to inject this?

  def __init__(self, util_instance):
    self._some_util_instance = util_instance # Is this the right way?

  def get(self, request, path):
    """ Handles GET calls """
    self._some_util_instance.some_method(path) # This is why I want this object injected.

  def post(self, request, path):
    """ Handles POST calls """

What is the best way to inject such an instance into my views class?

I could not find much about this in the documentation. I am familiar with using DI and IoC Containers. However, I am not sure how Django Rest Framework handles all of that.

Upvotes: 1

Views: 2094

Answers (2)

Isaac
Isaac

Reputation: 1536

It's not ideal and I don't know if this would work for your case, but you can do something like this. Giving that this is your class

class MyAPIView(APIView):
  """ My API """

  _some_util_instance = None # How to inject this?
    
  def get(self, request, path):
    """ Handles GET calls """
    self._some_util_instance.some_method(path) # This is why I want this object injected.

  def post(self, request, path):
    """ Handles POST calls """

In your urls.py you could inject the dependencies like this:

urlpatterns = [
    path(
        'your/cool/endpoint/',
        MyAPIView.as_view(_some_util_instance=SomeUtilInstance()),
        name='my-api-view'
    ),]

I haven't tried but I guess you could do the same in your tests, or just do some monkey patch there.

Upvotes: 0

Rich Tier
Rich Tier

Reputation: 9441

class MyAPIView(APIView):
    """ My API """

    _some_util_instance = MyUtilClass()

Or

class MyAPIView(APIView):
    """ My API """

    def __init__(self, *args, **kwargs):
        self._some_util_instance = MyUtilClass()
        super().__init__(self, *args, **kwargs)

Or

MyAPIView.as_view(
    _some_util_instance=MyUtilClass()
)

class MyAPIView(APIView):
    """ My API """

    _some_util_instance = None

Or

don't use a class as a container for your utility functions, just define them as module-level functions. This is my preferred approach.

Or

Use static/class methods

class MyUtilClass:
    """ Helps out with stuff """

    @classmethod
    def some_method(cls, path):
         print('I will now do things to the path: ', path)

Then you can simply call MyUtilClass.some_method(path) in the view without creating an instance of MyUtilityClass

Upvotes: 2

Related Questions