Search code examples
pythondjangoserializationdjango-rest-frameworkdjango-rest-viewsets

DRF: How to pass extra context data to serializers


I was searching the net and found the similar problem but it doesn't work in my case, Idk why. I try to put some extra data to context in serializer, but get only 3 default fields: request, view and format and no mention for my custom data.

My model:

class Match(models.Model):

sender = models.ForeignKey(
    Client,
    on_delete=models.CASCADE,
    related_name='senders'
)
recipient = models.ForeignKey(
    Client,
    on_delete=models.CASCADE,
    related_name='recipients'
)

class Meta:
    app_label = 'clients'
    db_table = 'matches'
    verbose_name = 'match'
    verbose_name_plural = 'matches'
    constraints = [
        models.UniqueConstraint(
            fields=['sender', 'recipient'],
            name='unique_match'
        )
    ]

My Serializer:

class MatchSerializer(serializers.ModelSerializer):

sender = serializers.HiddenField(default=serializers.CurrentUserDefault())

def validate(self, data):
    if data['sender'] == self.context['recipient']:
        raise serializers.ValidationError('You cannot match yourself')
    return data

def create(self, validated_data):

    return Match.objects.create(
        sender=validated_data['sender'],
        recipient=self.context['recipient']
    )

class Meta:
    model = Match
    fields = ['sender']`

My ModelViewSet:

class MatchMVS(ModelViewSet):
    queryset = Match.objects.all()
    serializer_class = MatchSerializer
    http_method_names = ['post']
    permission_classes = [IsAuthenticated]

    # without and with doesn't work
    def get_serializer_context(self):
        context = super(MatchMVS, self).get_serializer_context()
        context.update({
            "recipient": Client.objects.get(pk=23)
            # extra data
        })
        return context

    @action(detail=True, methods=['POST'], name='send_your_match')
    def match(self, request, pk=None):
        sender = request.user
        recipient = Client.objects.get(pk=pk)
        serializer = MatchSerializer(context={'request': request, 'recipient': recipient},
                                     data=request.data)

        data_valid = serializer.is_valid(raise_exception=True)
        if data_valid:
            recipient = serializer.save()

        is_match = Match.objects.filter(sender=recipient, recipient=sender).exists()
        if is_match:
            send_mail(
                f'Hello, {sender.first_name}',
                f'You got match with {recipient.first_name}! '
                f'Your`s partner email: {recipient.email}',
                settings.EMAIL_HOST_USER,
                [sender.email],
                fail_silently=False,
            )
            send_mail(
                f'Hello, {recipient.first_name}',
                f'You got match with {sender.first_name}! '
                f'Your`s partner email: {sender.email}',
                settings.EMAIL_HOST_USER,
                [recipient.email],
                fail_silently=False,
            )

            return Response(recipient.email, 201)
        else:
            return Response(f'Your sympathy has been sent to {recipient.username}.', 201)

I was debugging it through PyCharm and Postman but still can't understand where is my mistake. Hope you will help me to fix it.


Solution

  • Your code is right.It should work. But i don't know where is the issue.You can try the modified code as below.

    class MatchSerializer(serializers.ModelSerializer):
    
        def validate(self, data):
            if data['sender'] == data['recipient']:
                raise serializers.ValidationError('You cannot match yourself')
            return data
        class Meta:
            model = Match
    
            fields = ['sender', 'recipient']
    
    class MatchMVS(ModelViewSet):
        queryset = Match.objects.all()
        serializer_class = MatchSerializer
        http_method_names = ['post']
        permission_classes = [IsAuthenticated]
    
        @action(detail=True, methods=['POST'], name='send_your_match')
        def match(self, request, pk=None):
            sender = request.user
            recipient = Client.objects.get(pk=pk)
            serializer = MatchSerializer(data={**request.data, 'recipient': recipient.id})
    
            data_valid = serializer.is_valid(raise_exception=True)
            if data_valid:
                recipient = serializer.save()
    
            is_match = Match.objects.filter(sender=recipient, recipient=sender).exists()
            if is_match:
                send_mail(
                    f'Hello, {sender.first_name}',
                    f'You got match with {recipient.first_name}! '
                    f'Your`s partner email: {recipient.email}',
                    settings.EMAIL_HOST_USER,
                    [sender.email],
                    fail_silently=False,
                )
                send_mail(
                    f'Hello, {recipient.first_name}',
                    f'You got match with {sender.first_name}! '
                    f'Your`s partner email: {sender.email}',
                    settings.EMAIL_HOST_USER,
                    [recipient.email],
                    fail_silently=False,
                )
    
                return Response(recipient.email, 201)
            else:
                return Response(f'Your sympathy has been sent to {recipient.username}.', 201)