Django beginner here,
I have two similar endpoints as shown below, they differ in their url_path of the action decorator and the request parameters requester_id
and approval id
The problem
both /workflow_approvals/{requester_id}/
and /workflow_approvals/{approval_id}/
are routing to the requester method view(the first below)
@action(methods=['GET'], detail=False, serializer_class=WorkflowRequesterActivitySerializer, url_path='(?P<requester_id>[^/.]+)') def requester_activities(self, request, requester_id, pk=None): try: approval = WorkflowApproval.objects.filter(requester=requester_id).first() if approval is None: return Response({'success': False, 'errors': 'No workflow for specified requester'}, status=status.HTTP_404_NOT_FOUND) activities = WorkflowActivity.objects.filter( workflowapproval=approval ) serializer = self.get_serializer(activities, many=True) return Response({'success': True, 'data': {'total_count': activities.count(), 'activities': serializer.data}}, status=status.HTTP_200_OK) except Exception as e: return Response({'success': False, 'errors': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(methods=['GET'], detail=False, serializer_class=WorkflowActivitySerializer, url_path='(?P<approval_id>w+)',) def approval_activities(self, request, approval_id, pk=None): try: approval = WorkflowApproval.objects.filter(id=approval_id).first() if approval is None: return Response({'success': False, 'errors': 'Workflow Approval does not exist'}, status=status.HTTP_404_NOT_FOUND) activities = WorkflowActivity.objects.filter( workflowapproval=approval) serializer = self.get_serializer(activities, many=True) return Response({'success': True, 'data': {'total_count': activities.count(), 'activities': serializer.data}}, status=status.HTTP_200_OK) except Exception as e: return Response({'success': False, 'errors': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
my urls.py
file looks like this
from django.urls import include, path from rest_framework.routers import DefaultRouter from .views import WorkflowApprovalsViewset app_name = "workflow_approvals" router = DefaultRouter() router.register("", WorkflowApprovalsViewset) urlpatterns = [ path("", include(router.urls)), ]
Advertisement
Answer
Django doesn’t have a way of differentiating /workflow_approvals/{requester_id}/
and /workflow_approvals/{approval_id}/
, since the regex pattern for (?P<requester_id>[^/.]+)
matches both. So when you make the request with either a requester_id
or approval_id
, it’ll always end up routing to the former.
You will need instead differentiate the url_path
s somehow so they don’t collide. For instance, including an extra string in the path, like matching url_path='requester/(?P<requester_id>[^/.]+)')
and url_path='approval/(?P<approval_id>w+)')
. (You may want to check out the Routing for extra actions
example in the docs.)
But possibly better yet, since it seems you’re trying to filter your list results based on parameters, I’d recommend checking out the Filtering options in Django Rest Framework. You could do something like:
class WorkflowApprovalsViewset(...): filterset_fields = ("id", "requester_id",) filter_backends = [django_filters.rest_framework.DjangoFilterBackend]
and then be able to query via the standard list route, with query params like ?id=123
or ?requester_id=42
.