dfunckt / django-rules

Awesome Django authorization, without the database

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Assertion error when adding a post non-detail action

francipvb opened this issue · comments

Hello,

When adding a non-standard non-detail extra action to a viewset, the "AutoRulesPermissionViewSetMixin" raises an assertion error. Note that it only occurs if you map a post action to an already-defined get extra.

For example:

class PropertyViewSet(FilteredQuerySetMixing, CustomPermissionsMixing,
                      AutoPermissionViewSetMixin,
                      viewsets.ModelViewSet):
    "A viewset for property instances."
    queryset = models.Property.objects.all()
    serializer_class = serializers.PropertySerializer
    filterer = filterers.PropertyQuerysetFilterer
    permission_classes = [permissions.IsAuthenticated]

    permission_type_map = {
        **AutoPermissionViewSetMixin.permission_type_map,
        "superintendent": "change",
        "superintendents": "view",
        "create_superintendent": "add",
    }

    # Runs without problems
    @action(
        methods=["post"],
        detail=True,
        serializer_class=properties.SelectSuperintendentSerializer,
    )
    def select_superintendent(self, request, pk=None, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(True)
        prop = self.get_object()
        serializer.save(property=prop)
        return HttpResponseRedirect(reverse("property-detail", args=[prop.pk]))

    # And this does, too
    @action(
        detail=False,
        methods=["get"],
        queryset=models.properties.Superintendent.objects.all(),
        serializer_class=properties.SuperintendentSerializer,
    )
    def superintendents(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    # But this is never called
    @superintendents.mapping.post
    def create_superintendent(self, request, pk=None, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return HttpResponseRedirect(request.path)

        return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)

Cheers,

For completeness, I got this log:

Internal Server Error: /api/properties/superintendents/
Traceback (most recent call last):
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rest_framework\viewsets.py", line 114, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rest_framework\views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rest_framework\views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rest_framework\views.py", line 476, in raise_uncaught_exception
    raise exc
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rest_framework\views.py", line 493, in dispatch
    self.initial(request, *args, **kwargs)
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rules\contrib\rest_framework.py", line 70, in initial
    obj = self.get_object()
  File "C:\Users\Franci\.virtualenvs\vectormgt-8ezpdzdA\lib\site-packages\rest_framework\generics.py", line 88, in get_object
    assert lookup_url_kwarg in self.kwargs, (
AssertionError: Expected view PropertyViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
[19/Jun/2020 13:44:40] "POST /api/properties/superintendents/ HTTP/1.1" 500 110893

I think that the problem is in the line 70, where it says obj = self.get_object(). I{ve tracked the problem and it is likely to be caused by the previous erroneous condition checking.

Cheers,

I made a mistake, reopening...

Yeah - unless I'm missing something, the condition doesn't look correct.

extra_actions = self.get_extra_actions()
# We have to access the unbound function via __func__
if handler.__func__ in extra_actions:
if handler.detail:
obj = self.get_object()
elif self.action not in ("create", "list"):
obj = self.get_object()

It shouldn't be necessary to check the extra action handler function - the router should configure the view with the correct arguments. The condition should probably be:

if self.detail:
    obj = self.get_object()