Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework Read Only Model Serializer

I want to have a total read only ModelSerializer, i.e. just list/retrieve methods

what is the best way to do it?

like image 518
Mohsen Avatar asked Jul 12 '16 04:07

Mohsen


3 Answers

You really want to do this at the view (or Viewset) level, which you can do with a ReadOnlyModelViewSet.

(You mentioned this in your comment but I'm leaving it as an answer for better visibility).

For example (from the documentation):

from rest_framework import viewsets


class AccountViewSet(viewsets.ReadOnlyModelViewSet):
    """
    A simple ViewSet for viewing accounts.
    """
    queryset = Account.objects.all()
    serializer_class = AccountSerializer
like image 162
mgalgs Avatar answered Nov 17 '22 02:11

mgalgs


If you do need a serializer to be read only, it's most concise and stable option to override the init method:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    setattr(self.Meta, 'read_only_fields', [*self.fields])

In comparison with the above:

  • @mgalgs's solution is best, if a view irrespective of the serializer used should be read only.
  • @thisisms solution is best if you only have a few and non-dynamic fields
  • @D W's approach will only work if there are no writable serializer fields that use the 'source' keyword.

EDIT better solution: You can update the def get_fields method instead of the init method and create an abstract serializer:

class ReadOnlyModelSerializer(serializers.ModelSerializer):
    def get_fields(self, *args, **kwargs):
        fields = super().get_fields(*args, **kwargs)
        for field in fields:
            fields[field].read_only = True
        return fields

To use it, just inherit from the abstract serializer:

def MySerializer(ReadOnlyModelSerializer):
   class Meta:
       model = MyModel
       fields = '__all__'
like image 20
LukasKlement Avatar answered Nov 17 '22 03:11

LukasKlement


The only thing you have to do is create a serializer like this. serializers.py

class YourdataSerializer(serializers.ModelSerializer):
    class Meta:
        model = Yourdata
        # some data
        fields = ('id', 'city', 'pincode', 'created')
        read_only_fields = ('id', 'city', 'pincode', 'created')

Views something like this

class YourdataList(APIView):
    def get(self, request, format=None):
        yourdata = YourdataList.objects.all()
        serializer = YourdataSerializer(yourdata, many=True)
        return Response(serializer.data)

detail view

class YourdataDetail(APIView):
   def get_object(self, pk):
        try:
            return Yourdata.objects.get(pk=pk)
        except Yourdata.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = YourdataSerializer(snippet)
        return Response(serializer.data)

This will do it.

like image 13
thisisms Avatar answered Nov 17 '22 02:11

thisisms