MykolaSenechyn
MykolaSenechyn

Reputation: 90

Change list view output field in django rest framework

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

Answers (3)

zackcpetersen
zackcpetersen

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

DUMBA
DUMBA

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

Vishal Singh
Vishal Singh

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

Related Questions