Django REST Framework: Read-only and Write-only Fields in Serializers
Last updated 1 month, 2 weeks ago | 130 views 75 5

When building APIs using Django REST Framework (DRF), it's important to control how data is exposed and accepted. You may want certain fields to be visible in the response but not accepted in a request — or vice versa.
That’s where read-only and write-only fields come in.
What Are Read-only and Write-only Fields?
-
Read-only fields:
These appear in serialized output (e.g., GET responses) but are ignored in input (e.g., POST/PUT requests). -
Write-only fields:
These are accepted in incoming data (POST/PUT requests) but are excluded from responses (GET responses).
Why Use Them?
Here are some common use cases:
Scenario | Field Type |
---|---|
Auto-generated fields (like id , created_at ) |
read_only=True |
Password fields | write_only=True |
Metadata like author , created_by that shouldn’t be set manually |
read_only=True |
Sensitive input (e.g., token , security_answer ) |
write_only=True |
How to Define Read-only/Write-only Fields
Method 1: Field arguments
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField(write_only=True)
date_joined = serializers.DateTimeField(read_only=True)
Method 2: extra_kwargs
in ModelSerializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password', 'date_joined']
extra_kwargs = {
'password': {'write_only': True},
'date_joined': {'read_only': True}
}
Example: Register Serializer with Password
class RegisterSerializer(serializers.Serializer):
username = serializers.CharField()
email = serializers.EmailField()
password = serializers.CharField(write_only=True)
token = serializers.CharField(read_only=True)
def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=validated_data['password']
)
user.token = "generated-token"
return user
Response:
{
"username": "john",
"email": "[email protected]",
"token": "generated-token"
}
Request:
{
"username": "john",
"email": "[email protected]",
"password": "securepassword"
}
Note: The password
is accepted in the request but not returned. The token
is returned but not required in the request.
Tips & Best Practices
-
✅ Use
write_only=True
for any sensitive input (like passwords, PINs, etc.). -
✅ Use
read_only=True
for fields the client should not modify (likeid
, timestamps). -
✅ Combine
extra_kwargs
and direct field definitions as needed. -
✅ Don't return sensitive information — validate but keep it private.
⚠️ Common Pitfalls
Problem | Solution |
---|---|
Trying to write to a read-only field | Remove it from the incoming data |
Expecting write-only fields to appear in responses | Don’t — they’re intentionally hidden |
Forgetting to return the field in create() or update() |
Ensure values like tokens are set and returned manually |
Final Thoughts
Using read_only
and write_only
fields in DRF serializers gives you precise control over how data flows in and out of your API. It helps protect sensitive information, prevents misuse of API endpoints, and keeps your application logic clean and secure.
Whether you're handling user registrations, passwords, tokens, or metadata — mastering these serializer options is essential for robust API design.