Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assertion error when adding a post non-detail action #123

Open
francipvb opened this issue Jun 19, 2020 · 4 comments
Open

Assertion error when adding a post non-detail action #123

francipvb opened this issue Jun 19, 2020 · 4 comments

Comments

@francipvb
Copy link

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,

@francipvb
Copy link
Author

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,

@francipvb
Copy link
Author

I made a mistake, reopening...

@francipvb francipvb reopened this Jun 19, 2020
@rpkilby
Copy link
Contributor

rpkilby commented Jun 19, 2020

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()

@francipvb
Copy link
Author

francipvb commented Jun 20, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants