There is a Django project that uses a REST API.
Most of the url-patterns follow the same paradigm:
/foo_config/1
Basically /list-view/details-view
But there is another type of config - which can only have 1 object, so showing it like /bar_config/1
is confusing, because user might expect #2 and #3, etc.
I would like to 'map' bar_config
details and list together using simple /bar_config
.
Tried using @detail_route
, but it doesn't work:
@detail_route(methods=['put'])
def put_config(self, request):
...
How to achieve my goal?
UPDATE: after trying to play with detail_route
and Ivan Semochkin answer - still no luck. I will provide more details on what I have:
/accounts/foo_account/bar_config/
<-- list view
/accounts/foo_account/bar_config/1
<-- details view
Accounts defined as:
router = routers.DefaultRouter()
router.register('accounts', AccountViewSet)
The goal is to:
bar_config/1
on bar_config
(PUT on LIST page);bar_config/1
;I will summarize: I need to change the way a sub-link works in the existing project, that already uses DefaultRouter
for all its patterns. This sub-link maps singleton-model. I would like to show update (PUT) data on the list (GET) page.
Why don't you just override list
method?
class ConfigViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Config.objects.all()
serializer_class = ConfigSerializer
def retrieve(self, request, *args, **kwargs):
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
def list(self, request, *args, **kwargs):
instance = self.get_queryset().first()
# using 'first' will retrieve first instance
serializer = self.get_serializer(instance)
return Response(serializer.data)
It will work fine it you don't only show that model. If you want to provide some CRUD, then inherit from ModelViewSet
and override delete
and update
methods.
Update for comment
Another way to do it - create a custom router, with this router you don't need to use list
, use retrieve instead
from rest_framework.routers import Route, SimpleRouter
class CustomRouter(SimpleRouter):
"""
A router for update and retrieve without lookup field.
"""
routes = [
Route(
url=r'^{prefix}/$',
mapping={'put': 'update'},
name='{basename}-update',
initkwargs={'suffix': 'Update'}
),
Route(
url=r'^{prefix}/$',
mapping={'get': 'retrieve'},
name='{basename}-detail',
initkwargs={'suffix': 'Detail'}
),
]
ViewSet:
class ConfigViewSet(viewsets.ModelViewSet):
queryset = Config.objects.all()
serializer_class = ConfigSerializer
def retrieve(self, request, *args, **kwargs):
instance = self.get_queryset().first()
# using 'first' will retrieve first instance
serializer = self.get_serializer(instance)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
instance = self.get_queryset().first()
serializer = self.get_serializer(instance, data=request.data)
# you could also provide `partial=True` in serializer for partial update
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
urls:
router = CustomRouter()
router.register('config', ConfigViewSet)
urlpatterns = router.urls
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With