I'm super new to Python/Django/Django-REST, but I've managed to follow the tutorial and create my own API similar to the tutorial.
In my app, I have a model called Toggle
, with a unique field called feature_key
.
Following the tutorial, the default way to get a Toggle
is by using the ID, i.e.
http://127.0.0.1:8000/toggles/1/
And it shows up in the browsable API page as a clickable link.
My question is, how do I add another endpoint to directly get a toggle via its feature_key
? Maybe something like:
http://127.0.0.1:8000/toggles/key/category.key_1/
(I'm not sure if this is a "correct" way to design API)
How do I make this endpoint to be visible in the browsable API so that other devs are aware that this endpoint exists?
toggle/views.py
:
This is almost the same as the tutorial's view.py
# imports here
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'toggles': reverse('toggle-list', request=request, format=format)
})
class ToggleViewSet(viewsets.ModelViewSet):
queryset = Toggle.objects.all()
serializer_class = ToggleSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
toggle/serializers.py
:
Also similar to the tutorial
class ToggleSerializer(serializers.HyperlinkedModelSerializer):
created_by = serializers.ReadOnlyField(source='created_by.username')
is_enabled = serializers.BooleanField(initial=True)
class Meta:
model = Toggle
fields = ['url', 'id', 'feature_key', 'description', 'is_enabled', 'created_at', 'created_by']
class UserSerializer(serializers.HyperlinkedModelSerializer):
toggles = serializers.HyperlinkedRelatedField(many=True, view_name='toggle-detail', read_only=True)
class Meta:
model = User
fields = ['url', 'id', 'username', 'toggles']
toggle/urls.py
:
Same as tutorial
router = DefaultRouter()
router.register(r'toggles', views.ToggleViewSet)
router.register(r'users', views.UserViewSet)
urlpatterns = [
path('', include(router.urls)),
]
I checked the tutorial...
You can make following changes: urls.py
replace this
path('toggles/<int:pk>/', views.toggles_function),
with this:
path('toggles/<feature_key>/', views.toggles_function),
views.py
@csrf_exempt
def snippet_detail(request, key):
try:
snippet = Snippet.objects.get(feature_key=key)
except Snippet.DoesNotExist:
return HttpResponse(status=404)
you can get the link http://127.0.0.1:8000/toggles/<feature_key of entry>/
if you want link like this
http://127.0.0.1:8000/toggles/key/category.key_1/
in urls.py
path('toggles/<pk>/<feature_key>/', views.toggles_function),
and in views.py
@csrf_exempt
def snippet_detail(request, pk, key):
try:
snippet = Snippet.objects.get(feature_key=key) # snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return HttpResponse(status=404)
suggestion
You don't need use two fields from same model in url (like pk and feature_key both) if both are unique fields. You can get the instance from any of them.