I re-use an existing drf model viewset but there are some custom actions (assigned with @action label) that i don't need. How can I hide/remove it from django rest framework without modifying the origional model viewset?
for example
class MyViewSet(viewsets.ModelViewSet):
@action(["get",], detail=False)
def custom_a(self, request):
# some stuff
@action(["get",], detail=False)
def custom_b(self, request):
# some stuff
@action(["get",], detail=False)
def custom_c(self, request):
# some stuff
My router
router = routers.SimpleRouter()
router.register("dummies", views.MyViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Then I will have these endpoints
GET /dummies/
GET /dummies/{id}/
POST /dummies/
PUT /dummies/{id}/
PATCH /dummies/{id}/
DELETE /dummies/{id}/
GET /dummies/custom_a/
GET /dummies/custom_b/
GET /dummies/custom_c/
Now how can I just keep 5 first views and GET /dummies/custom_a/ ?
Thanks.
There are a few ways to do this, but the "cleanest" seems overriding.
Decorators are not "inherited", so you can just re-declare the method on your derived class. This new method takes precedence over the base class method, so DRF no longer sees them as @action
s.
class View1(viewsets.ModelViewSet):
@action(['get'], detail=False)
def act_up(self, request):
pass
class Meta:
model = Client
fields = "__all__"
class View2(View1):
# redefine and don't add the @action decorator
def act_up(self, request):
pass
class Meta:
model = View1.Meta.model
fields = View1.Meta.fields
Router URLs are calculated once and then cached. You could make this happen, then filter out the ones you don't want (by name)
router = SimpleRouter()
router.register("view1", View1, basename="v1")
router._urls = [
r for r in router.urls
if not any(r.name.endswith(bad) for bad in ['-act-up', '-other-rt']
]
You can manually create the routes you need, in the same manner that the base SimpleRouter
does. This is a lot more work, and most certainly not worth it
list_paths = View1.as_view({"get": "list"})
detail_paths = View1.as_view({"get": "retrieve", "patch": "partial_update"})
urlpatterns = [
path("view1/", list_paths, name="view1-list"),
path("view1/<int:pk>/", detail_paths, name="view1-detail")
]
What this does is bind a url + http method
(eg get
) to a specific DRF "action" (list/retrieve/destroy,etc). So GET view11/
calls your viewset with action=list
, which the viewset then dispatches to the correct method internally.
Since you only map the things you want, there is no way for those bad "other" methods to be called.
It is a bit trickier, and confusing, and makes you responsible for the routing which, together, make it more work to maintain & understand. If there is no other way, or if you only want 1 or 2 methods from the ViewSet, then its an OK option.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.