DRF:如何将额外的上下文数据传递给序列化程序

DRF: How to pass extra context data to serializers

我在网上搜索并找到了类似的 ,但它在我的情况下不起作用,我不知道为什么。 我尝试在序列化程序中将一些额外数据放入 context,但只得到 3 个默认字段:requestviewformat,没有提及我的自定义数据。

我的模特:

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'
        )
    ]

我的序列化程序:

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']`

我的模型视图集:

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)

我正在通过 PyCharm 和 Postman 进行调试,但仍然无法理解我的错误在哪里。希望你能帮我解决它。

您的代码 right.It 应该可以工作。但是我不知道在哪里 issue.You 可以试试下面修改后的代码。

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)

问题是我自己不注意,错误的viewset被链接到url

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

而不是:

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