Ashish Gupta
Ashish Gupta

Reputation: 2614

read_only field in django rest serializer with unique_together contraint

I wanted to make email field unique in default django User model. So i made it unique_together=[('email',)] . Now in serializer I want it to be a read_only field. But Django Rest Framework 3.0 docs says:

There is a special-case where a read-only field is part of a unique_together constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user.

The right way to deal with this is to specify the field explicitly on the serializer, providing both the read_only=True and default=… keyword arguments.

One example of this is a read-only relation to the currently authenticated User which is unique_together with another identifier. In this case you would declare the user field like so:

user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())

serializers.CurrentUserDefault() represents the current user.I want to set default as user's email . Isn't serializers.CurrentUserDefault() equivalent to request.user . serializers.CurrentUserDefault().email is giving error 'CurrentUserDefault' object has no attribute 'email' How to set email default as user's email ?

Upvotes: 3

Views: 3272

Answers (2)

Graphic D. Thanh
Graphic D. Thanh

Reputation: 31

Please check solution 2 from this answer

The code can be:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'email',)
        extra_kwargs = {
            'email': {'read_only': True},
        }


    def create(self, validated_data):
        """Override create to provide a email via request.user by default."""
        if 'email' not in validated_data:
            validated_data['email'] = self.context['request'].user.email

        return super(UserSerializer, self).create(validated_data)

hope it help :)

Upvotes: 2

Arpit Goyal
Arpit Goyal

Reputation: 2254

This is what the documentation of CurrentUserDefault says:

A default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer.

You can either do that or you can provide the email id passed in the context data in your views. Override the function get_serializer_context

def get_serializer_context(self):
    context = super(YourClass, self).get_serializer_context()
    context['email'] = request.user.email

    return context

in your views. Your view should be extended from GenericAPIView at some level of inheritance. Now in your serializer, override your __init__ and get your email data.

def __init__(self, instance = None,  data = serializers.empty, *args, **kwargs):
    self.email = kwargs['context']['email']

Now you can use that in your serializer.

Upvotes: 2

Related Questions