Home > OS >  DRF: How to pass extra context data to serializers
DRF: How to pass extra context data to serializers

Time:03-29

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.

CodePudding user response:

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)

CodePudding user response:

The problem was my own inattention, the wrong viewset was linked to the url

urlpatterns = [
    path('clients/<int:pk>/match', views.MatchCreateAPIView.as_view(), name='get_match')
]

instead of:

urlpatterns = [
    path('clients/<int:pk>/match', views.MatchMVS.as_view({'post': 'match'}), name='get_match')
]
  • Related