使用@action装饰器时DRF出现DELETE方法不允许的问题
You’re facing a routing conflict because Django processes URL patterns in sequential order. Your two identical URL paths mean the first one always gets matched: when GET is first, DELETE requests hit a path only configured for GET (hence the "Method not allowed" error), and swapping order reverses which method works.
Combine both method mappings into a single URL path, and adjust your viewset for better alignment with DRF conventions.
Step 1: Fix URL Configuration
Replace the two separate path entries with one that maps both HTTP methods to their respective actions:
path('reporting/reports/<str:report_id>', ReportView.as_view({ "get": "get_report", "delete": "delete_reports" }), name="report_actions"),
Step 2: Optimize ViewSet (Recommended)
Since your actions target a specific report by report_id, use detail=True in the @action decorator to signal a single-instance action. If report_id isn’t your model’s primary key, set lookup_field to match:
from rest_framework import viewsets class ReportView(viewsets.ViewSet): lookup_field = "report_id" # Match your model's identifier field @action(methods=["GET"], detail=True) def get_report(self, request, report_id=None): # Your GET logic here pass @action(methods=["DELETE"], detail=True) def delete_reports(self, request, report_id=None): # Your DELETE logic here pass
Alternative: Use Built-in ViewSet Methods
If your actions are just retrieving and deleting reports, skip custom actions and override DRF’s default methods:
class ReportView(viewsets.ModelViewSet): queryset = Report.objects.all() serializer_class = ReportSerializer lookup_field = "report_id" def retrieve(self, request, report_id=None): # Custom GET logic (or use super() for default behavior) return super().retrieve(request, report_id) def destroy(self, request, report_id=None): # Custom DELETE logic (or use super() for default behavior) return super().destroy(request, report_id)
Then simplify your URL path to map directly to these built-in methods:
path('reporting/reports/<str:report_id>', ReportView.as_view({ "get": "retrieve", "delete": "destroy" }), name="report_actions"),
Combining method mappings into one URL path lets Django route both GET and DELETE requests to their correct handlers without conflict. Using detail=True ensures your code follows DRF’s design patterns, making it more maintainable.
内容的提问来源于stack exchange,提问作者Pratik Sharma

