Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

django - Changing serializer fields on the fly

For example I have the following serializer:

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = (
            'userid',
            'password'
        )

But I don't want to output password on GET (there are other fields in my real example of course). How can I do that without writing other serializer? Change the field list on the fly. Is there any way to do that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You appear to be looking for a write-only field. So the field will be required on creation, but it won't be displayed back to the user at all (the opposite of a read-only field). Luckily, Django REST Framework now supports write-only fields with the write_only attribute.

In Django REST Framework 3.0, you just need to add the extra argument to the extra_kwargs meta option.

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = (
            'userid',
            'password'
        )
        extra_kwargs = {
            'password': {
                'write_only': True,
            },
        }

Because the password should be hashed (you are using Django's user, right?), you are going to need to also hash the password as it is coming in. This should be done on your view, most likely by overriding the perform_create and perform_update methods.

from django.contrib.auth.hashers import make_password

class UserViewSet(viewsets.ViewSet):

    def perform_create(self, serializer):
        password = make_password(self.request.data['password'])

        serializer.save(password=password)

    def perform_update(self, serializer):
        password = make_password(self.request.data['password'])

        serializer.save(password=password)

In Django REST Framework 2.x, you need to completely redefine the password field on the serializer.

class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = (
            'userid',
            'password'
        )

In order to hash the password ahead of time in Django REST Framework 2.x, you need to override pre_save.

from django.contrib.auth.hashers import make_password

class UserViewSet(viewsets.ViewSet):

    def pre_save(self, obj, created=False):
        obj.password = make_password(obj.password)

        super(UserViewSet, self).pre_save(obj, created=created)

This will solve the common issue with the other answers, which is that the same serializer that is used for creating/updating the user will also be used to return the updated user object as the response. This means that the password will still be returned in the response, even though you only wanted it to be write-only. The additional problem with this is that the password may or may not be hashed in the response, which is something you really don't want to do.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...