Himanshu Shankar
Himanshu Shankar

Reputation: 745

DJango REST Framework Read Only field

I have a field owner that is a ForeignKey to User model.

This field is required at the time of creation. But it can not be changed later on.

How to make fields Non-Editable? Is there any other way than creating multiple serializers?

Garage Model

class GarageDetails(models.Model):
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, )
    name = models.CharField(_('Garage Name'), max_length=254, blank=False, null=False, unique=True)
    price = models.IntegerField(_('Price'), blank=False)
    available_from = models.TimeField(_('Available From'), default=datetime.time(6, 00), blank=False)
    available_till = models.TimeField(_('Available till'), default=datetime.time(18, 00), blank=False)
    description = models.TextField(_('Garage Description'), blank=True, null=True)

    create_date = cmodels.UnixTimestampField(_('Date Added'), auto_now_add=True)
    update_date = cmodels.UnixTimestampField(_('Date Added'), auto_created=True)
    is_available = models.BooleanField(_('Available'), default=True)

Serializer

class UserFKSerializer(serializers.ModelSerializer):

    class Meta:
        model = get_user_model()
        fields = ('id', 'name', 'email', 'mobile')


class GarageSerializer(serializers.ModelSerializer):
    owner = UserFKSerializer(many=False, read_only=True)

    class Meta:
        model = GarageDetails
        fields = '__all__'
        read_only_fields = ('id', 'owner', 'create_date', 'update_date')

Views

class GarageRegister(generics.ListCreateAPIView):
    renderer_classes = (JSONRenderer, )
    permission_classes = (IsAuthenticated, )

    @csrf_exempt
    def post(self, request, *args, **kwargs):
        serialize = GarageSerializer(data=request.data)
        if serialize.is_valid():
            # Create Garage with owner & name

class GarageUpdate(generics.ListCreateAPIView):
    renderer_classes = (JSONRenderer, )
    permission_classes = (IsAuthenticated, )

    @csrf_exempt
    def post(self, request, *args, **kwargs):
        serialize = GarageSerializer(data=request.data)
        if serialize.is_valid():
            # Update Garage but can't update create_date, id, owner & name

Upvotes: 11

Views: 12270

Answers (2)

John Gilmore
John Gilmore

Reputation: 456

You can do this by overriding the "update" method as follows:

  def update(self, instance, validated_data):                                                     
      if 'owner' in validated_data:                                                              
          del validated_data['owner']                                                            
      return super().update(instance, validated_data)

This will silently ignore the owner field on updates. If you want to you may instead "raise ValidationError('owner may not be set on updates')" but if you do so you may want to read the model instance and only raise the error if it's actually a change to avoid false positives.

Also, if you're using the python2, the "super" call needs to be "super(GarageSerializer, self)" or some such.

Upvotes: 1

DRC
DRC

Reputation: 5048

You could create a different model serializer for each use case (update, create):

specifying that field in read_only_fields in your model serializer:

class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = ('a', 'nother', 'field')
        read_only_fields = ('owner',)

for django forms instead you set the disabled field:

class MyModelForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       form.fields['owner'].widget.attrs['disabled'] = True

Upvotes: 6

Related Questions