Write only, read only fields in django rest framework

Solution 1:

The Django Rest Framework does not have Meta attribute write_only_fields anymore

According to their docs you set write-only fields in extra_kwargs

e.g

class UserSerializer(ModelSerializer):
    """
    ``Serializer`` for ``User`` ..
    """

    class Meta:
        model = User
        fields = ('id', 'email', 'first_name', 'last_name' ,'security_question', 'security_question_answer', 'password', 'is_active', 'is_staff')
        read_only_fields = ('is_active', 'is_staff')
        extra_kwargs = {
            'security_question': {'write_only': True},
            'security_question_answer': {'write_only': True},
            'password': {'write_only': True}
        }

Update

As @AKHIL MATHEW highlighted in his answer below

From DRF v3 onwards, setting a field as read-only or write-only can use serializer field core arguments mentioned as follows.

write_only

Set this to True to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.

Defaults to False Eg:

company = serializers.PrimaryKeyRelatedField(write_only=True)

Solution 2:

In accordance with the Django REST Framework documentation:

The write_only_fields option on ModelSerializer has been moved to PendingDeprecation and replaced with a more generic extra_kwargs

that's why it's recommended to do like this: you should use extra_kwargs:

extra_kwargs = {
    'model_b_ids': {'write_only': True},
    'another_field': {'read_only': True}
}

or:

 model_b_ids = serializers.IntegerField(write_only=True)

Solution 3:

Probably you're overseeing that your ModelA has the property modelb_set. In Django you describe the relationship in one model class. Django offers a backward relationship by lower-casing the target model and suffixing it with _set. So you could do:

a = ModelA.objects.get(pk=1)
a.modelb_set.all()

This would get the element with ID (or primary key) 1 from ModelA and retrieve all related ModelB elements.

You can set a value for related_name to overwrite the default value:

class ModelB(models.Model):
    f1 = models.CharField()
    model_a = models.ForeignKey(ModelA, related_name='model_b')

In DRF you can slightly adapt your serializer:

class ASerializer(serializers.ModelSerializer):
    model_b = serializers.PrimaryKeyRelatedField(many=True, read_only=False)

    class Meta:
        model = ModelA
        write_only_fields = ('model_b',)

With serializers.CharField() you can't post values and write them to the model, because it isn't a model field.

Give this example a try. Tinker and experiment. It should bring you closer to the solution.

EDIT: I'm not really sure how Django creates the name for backward relationship for PascalCase class names. Is it model_b_set for ModelB? Or is it modelb_set? You can try and find it out.