10

I want to do the following:

models.py

class MyModel(TimeStampedModel, models.Model):
    name = models.CharField(max_length=100)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL)

serializers.py

class MyModelSerializerCreate(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = (
            'name',
        )

And I would like to add as owner the current user in request.user. Currently I am adding this in my view directly by uptading request.data with user and then pass the updated data to my serializer.

    data = request.data
    # Add owner to data
    data["owner"] = request.user.pk
    serializer = self.get_serializer(data=data)
    serializer.is_valid(raise_exception=True)
    self.perform_create(serializer)
    headers = self.get_success_headers(serializer.data)

I would like to do this in my serializer directly but can't find a way to properly do it because it looks like data validation to me. Is this a good idea ? Should I keep this logic in my views or move it to my serializer ?

3 Answers 3

22

You can get a user from serializer context:

self.context['request'].user
It is passed from a method get_serializer_context which originally created in a GenericAPIView:

class GenericAPIView(APIView):
    ....
    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return {
            'request': self.request,
            'format': self.format_kwarg,
            'view': self
        }  

Inside a serializer you need to override a create method:

class MyModelSerializerCreate(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = ('name', )
 
    def create(self, validated_data):
        validated_data['owner'] = self.context['request'].user
        return super(MyModelSerializerCreate, self).create(validated_data)

You could also override an update and delete methods if you need some special interactions with the User model.

Sign up to request clarification or add additional context in comments.

5 Comments

Hum this looks good but it overrides the create function of the ModelSerializer which does a lot of things like managing many_to_many relationship for example. It would be cool if I could put my user directly into validated_data
@v.thorey so you could update validated_data and then call super for provide all default behavior or you could use perform_create method in you view. I'll update my answer
@IvanSemochkin I have the same problem, but your answer somehow doesn't work for me. I basically want to do: def perform_create(self, serializer): serializer.save(user=self.request.user) But if I do what you answered I get the error: "user": [ "This field is required." ]
@J.Hesters maybe you have a user in a fields tuple so validate method want you to provide a user before create
@IvanSemochkin Thank you! I was struggling with the Error-Message that user is required, but it was not because the Model requires it, but the fields of the serializer specified it as required.
4

Unfortunatly I dont have the reputation points to comment on @ivan-Semochkin post above, but should the last line not be:

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

Comments

2

The solution from Ivan Semochkin did not work for me, as it never entered into the create() method of the serializer. As request.data field is immutable, you need to copy it and then extend it.

from django.http import HttpRequest
from rest_framework.request import Request

class MyModelViewSet(ModelViewSet):
    def _extend_request(self, request):
        data = request.POST.copy()
        data['owner'] = request.user
        request_extended = Request(HttpRequest())
        request_extended._full_data = data

    def create(self, request, *args, **kwargs):
        request_extended = self._extend_request(request)
        return super().create(request_extended, *args, **kwargs)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.