menu

Questions & Answers

Is there a way to show only some model fields?

I have a model with field instances and have views. Can i make so that when you redirect to to main page you can see only ID, title, deadline, done? But when you redirect to the detail page you can see all the model fields.

models.py:

class Task(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    body = models.TextField()
    deadline = models.DateTimeField()
    done = models.BooleanField()

views.py :

lass TaskList(generics.ListCreateAPIView):
    # permission_classes = (IsAuthorOrReadOnly,)
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

class TaskDetail(generics.RetrieveUpdateDestroyAPIView):
    # permission_classes = (IsAuthorOrReadOnly,)
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

serializers.py:

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        fields = (
            "id",
            "title",
            "body",
            "author",
            "deadline",
            "done",
        )
        model = Task

urls.py:

urlpatterns = [
    path("<int:pk>/", TaskDetail.as_view(), name="task_detail"),
    path("", TaskList.as_view(), name="task_list"),
]

Please add a link to useful reading materials

Answers(1) :

Dynamically Modifying Fields:

Once a serializer has been initialized, the dictionary of fields that are set on the serializer may be accessed using the .fields attribute. Accessing and modifying this attribute allows you to dynamically modify the serializer.

Modifying the fields argument directly allows you to do interesting things such as changing the arguments on serializer fields at runtime, rather than at the point of declaring the serializer.

Following the example on the above documentation:

serializers.py

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super().__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

class TaskSerializer(DynamicFieldsModelSerializer):
    class Meta:
        fields = (
            "id",
            "title",
            "body",
            "author",
            "deadline",
            "done",
        )
        model = Task

On views.py you can either override get provided by ListCreateAPIView or list method provided by ListModelMixin, like in this example and in the following codeblock:

views.py

class TaskList(generics.ListCreateAPIView):
    # permission_classes = (IsAuthorOrReadOnly,)
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

    def list(self, request):
        # Note the use of `get_queryset()` instead of `self.queryset`
        queryset = self.get_queryset()
        serializer = TaskSerializer(queryset, many=True, fields=('id', 'title', 'deadline'))
        return Response(serializer.data)

        
class TaskDetail(generics.RetrieveUpdateDestroyAPIView):
    # permission_classes = (IsAuthorOrReadOnly,)
    queryset = Task.objects.all()
    serializer_class = TaskSerializer