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.
django-rules/rules/contrib/rest_framework.py
Lines 64 to 70 in 55cd1df
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()