0

Please Note this is a very Django specific question, so if you know the Django Rest Framework you will understand it

So I have a view in Django rest framework with an update function over ridden and a _has_permission helper function

def update(self, request, *args, **kwargs):
        permission, message = self._has_permission(data=request.data)
        if not permission:
            return Response({'error': message}, status=status.HTTP_403_FORBIDDEN)

        return super().update(request, *args, **kwargs)



    def _has_permission(self, data):
        """
       Resolves if the logged in user has permission to update the data given the type of data
       :param data:
       :return:
       """


        data['user_type'] = data['user_type'] if ('user_type' in data and data['user_type']) else None

        ....
        some checks
        ....
        return True, 'Has Permission'

In the case where the function _has_permission() sees that 'user_type' is not in data, it sets data['user_type'] = None in the function, but when it comes out request.data['user_type'] now exists and becomes None as well

How is this dictionary being shared across two different scopes. I thought functions have their own scopes

Dr Manhattan
  • 13,537
  • 6
  • 45
  • 41

2 Answers2

1

Contrary to your assertion, this is not at all specific to DRF, but a very general Python principle.

Passing any argument to a function always passes the object itself. If you then mutate that object in the function, all other references to that object will see that modification, because they remain references to the same object.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
0

By default, in Python, all args are passed by reference (or a kind of), which mean, you are passing a reference to the object, not a copy, so if you alter the object inside a function, you are affecting the object itself, not a copy of it. You can see more details at http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/

trinchet
  • 6,753
  • 4
  • 37
  • 60