I use DRF ModelViewSet for user account CRUD operations. I have "extend" Django user model with Profile model to store complementary user's informations. I have override create and update methods in my serializer to manage nested (related) fields of Profile model.
Using GET and POST methods is OK. In POST, password is correctly created and store (encrypted PBKDF2) in my Postgresql database.
My issue deals with PUT and PATCH methods. When using PATCH or PUT methods, when submitting password and password2, password is stored in database as plaintext.
I've try using make_password() and set_password(make_password()) but neither works. I've read DRF documentation and read many posts in SO but could not find any explanation.
Hope someone could explain this behavior and maybe haw to resolve this issue.
Serializers.py
class RegisterSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(required=True)
email = serializers.EmailField(required=True,validators=[UniqueValidator(queryset=User.objects.all())])
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
days_since_joined = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('username', 'password', 'password2', 'email', 'first_name', 'last_name', 'profile', 'days_since_joined')
extra_kwargs = {
'first_name': {'required': True},
'last_name': {'required': True}
}
def validate(self, attrs):
password = attrs.get('password')
password2 = attrs.get('password2')
if password and password != password2:
raise serializers.ValidationError({"password": "Password fields didn't match."})
return attrs
def get_days_since_joined(self, obj):
return (now() - obj.date_joined).days
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name']
)
# create profile
Profile.objects.create(
user=user,
qr_code=profile_data.get('qr_code'),
backup=profile_data.get('backup'),
role_in_study=profile_data.get('role_in_study'),
)
user.set_password(validated_data['password'])
user.save()
return user
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile', {})
profile = instance.profile
for key, value in profile_data.items():
setattr(profile, key, value)
profile.save()
return super().update(instance, validated_data)