Reputation: 90
I'm new to the Django and the Django Rest Framework, and having some issues figuring this one out.
I've got a Model of Workouts
, which contains a title and a many to many relationship field exercises
.
When making the api for the model, I'm inheriting the viewsets.ModelViewSet
class - which from my understanding setups the common uses for a rest api (List, Create, Update etc.).
This is fine however, when accessing /api/workouts/
I get a list of all the workouts including all the exercises assigned to the workout, I feel it's a bit of a waste to pull in all that exercise data and the user might never see it.
I would prefer to have a the /api/workouts/
not return exercises
and it only does so if a user accesses a workout with /api/workouts/1
the exercises will show up.
My serializer class,
class WorkoutSerializer(serializers.ModelSerializer):
exercises = ExerciseSerializer(read_only=True, many=True)
class Meta:
model = Workout
fields = ('id', 'title', 'exercises')
My view,
class WorkoutView(viewsets.ModelViewSet):
queryset = Workout.objects.all()
serializer_class = WorkoutSerializer
def list(self, request):
workouts_list = self.get_queryset().defer('exercises');
serializer = self.get_serializer(workouts_list, many=True)
return response.Response(serializer.data)
My latest attempt is to overwrite the list method and remove the field with the queryset, but it seems anything I do remove the field has no affect.
TL;DR I would like to keep using the ModelViewSet
but remove the field exercises
from the main list view /api/workouts/
and keep it in the detail view /api/workouts/1/
Thanks in advance, for any suggestions.
Upvotes: 2
Views: 1737
Reputation: 81
One possible solution is to create a separate viewset and serializer for the detail view vs. the list view.
in api/viewsets.py
Class WorkoutListView(viewsets.ModelViewSet):
queryset = Workout.objects.all()
serializer_class = WorkoutListSerializer
Class WorkoutDetailView(viewsets.ModelViewSet):
queryset = Workout.objects.all()
serializer_class = WorkoutDetailSerializer
in api/serializers.py
class WorkoutListSerializer(serializers.ModelSerializer):
class Meta:
model = Workout
fields = ('id', 'title')
class WorkoutDetailSerializer(serializers.ModelSerializer):
exercises = ExerciseSerializer(read_only=True, many=True)
class Meta:
model = Workout
fields = ('id', 'title', 'exercises')
in api/urls.py - this is the important part. Do the router.register() as normal for the list view
router.register(r'workouts', viewsets.WorkoutListView)
but then you'll need to define a path
for the detail view with the pk.
from django.urls import path
urlpatterns = [
path('workouts/<pk>/', viewsets.WorkoutDetailView.as_view({'get': 'retrieve'}))
]
at this point just make sure you include your url_patterns to your api and you should be good to go!
Upvotes: 0
Reputation: 179
exercises = ExerciseSerializer(read_only=True, many=True)
will always give you a queryset for your excercises as it will be like calling it as
@property
def excercises(self):
return self.excercises.all()
and then its always going to give you a queryset with all fields
I assume your model has a string method and all you want is to at least a name of the excercise or id. If so then this:
exercises = serializers.StringRelatedField(many=True)
will help you
Upvotes: 0
Reputation: 6234
Instead of inhering from ModelViewSet
, you can create your own custom class by inhereting from all parent classes of ModelViewSet
except ListModelMixin
.
from rest_framework import mixins
class MyCustomModelViewSet(
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet,
):
pass
Upvotes: 1