You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Django REST Framework序列化器返回自定义JsonResponse?

解决Django REST Framework返回自定义响应并调用外部API的方案

核心思路

ModelViewSet的默认update方法会返回序列化器处理后的模型实例数据,要实现自定义响应,需要重写视图的update方法,在其中完成:

  1. 执行原有业务逻辑(创建交易、通知)
  2. 调用外部API并处理响应
  3. 构造包含自定义内容和外部API响应的JSON返回

具体代码修改

1. 修改序列化器(保存业务数据引用)

在序列化器的update方法中,将创建的交易和通知实例保存到序列化器对象中,方便后续视图获取:

from rest_framework import serializers
from rest_framework.exceptions import PermissionDenied
from django.utils import timezone
from .models import User, BankingTransaction, Notifications

class SendMoneyExternalSerializer(serializers.ModelSerializer):
    def update(self, instance, validated_data):
        # 权限验证
        requesting_user = str(self.context['request'].user)
        if requesting_user != str(instance.username) and requesting_user not in instance.userprofile.banking_write:
            raise PermissionDenied('You do not have permission to update')

        # 提取请求参数
        account_number = self.context['request'].data['to_account']
        amount = self.context['request'].data['amount']
        to_bank = self.context['request'].data['to_bank']
        description = self.context['request'].data['description']
        trans_reference = self.context['request'].data['trans_reference']
        status = self.context['request'].data['status']

        # 创建交易记录并保存到序列化器实例
        self.transaction = BankingTransaction.objects.create(
            user=instance,
            date=timezone.now(),
            from_account_num=instance.userprofile.account_number,
            from_account_name=instance.userprofile.company,
            to_account=account_number,
            to_bank=to_bank,
            amount_transferred=amount,
            description=description,
            trans_reference=trans_reference,
            status=status,
        )

        # 更新通知计数
        instance.userprofile.notification_count += 1
        instance.userprofile.save()

        # 创建通知并保存到序列化器实例
        self.notification = Notifications.objects.create(
            user=instance,
            date=timezone.now(),
            read=False,
            message=f'You have paid N{amount} to account number {account_number} ({to_bank})'
        )
        
        return instance

    class Meta:
        model = User
        fields = ['pk']

2. 重写视图的update方法(处理外部API和自定义响应)

在视图中重写update方法,完成外部API调用并构造自定义响应:

from django.http import JsonResponse
import requests
from rest_framework import status
from rest_framework.viewsets import ModelViewSet
from .models import User
from .serializers import SendMoneyExternalSerializer

class sendmoney_external(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = SendMoneyExternalSerializer
    lookup_field = 'username'

    def update(self, request, *args, **kwargs):
        # 获取目标用户实例
        instance = self.get_object()
        # 初始化序列化器并执行业务逻辑
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # ---------------------- 调用外部API ----------------------
        # 替换为实际外部API地址
        external_api_url = "https://your-external-api-domain.com/transaction-endpoint"
        # 构造外部API请求参数(根据API要求调整)
        external_payload = {
            "from_account": instance.userprofile.account_number,
            "to_account": request.data.get('to_account'),
            "amount": request.data.get('amount'),
            "bank_code": request.data.get('to_bank'),
            "reference": request.data.get('trans_reference')
        }

        try:
            # 发送请求到外部API(根据API要求调整请求方法,如GET/PUT)
            external_response = requests.post(
                external_api_url,
                json=external_payload,
                # 如果API需要认证,添加headers
                # headers={"Authorization": "Bearer YOUR_API_KEY"},
                timeout=10
            )
            external_response.raise_for_status()  # 触发HTTP错误异常
            external_api_data = external_response.json()
        except requests.exceptions.RequestException as e:
            # 处理外部API调用失败的情况
            return JsonResponse(
                {
                    "status": "failed",
                    "message": f"External API call failed: {str(e)}",
                    "internal_transaction_id": serializer.transaction.id
                },
                status=status.HTTP_503_SERVICE_UNAVAILABLE
            )

        # ---------------------- 构造自定义响应 ----------------------
        custom_response = {
            "status": "success",
            "message": "Transaction processed successfully",
            "internal_transaction": {
                "id": serializer.transaction.id,
                "amount": serializer.transaction.amount_transferred,
                "to_account": serializer.transaction.to_account,
                "created_at": serializer.transaction.date.isoformat()
            },
            "external_api_result": external_api_data
        }

        return JsonResponse(custom_response, status=status.HTTP_200_OK)

关键注意事项

  • 先安装requests库:pip install requests
  • 外部API的请求方法、参数、认证方式需根据实际文档调整
  • 异常处理要覆盖超时、HTTP错误、JSON解析失败等场景
  • 如果需要更严谨的权限验证,可以将权限逻辑移到视图的check_object_permissions方法中
  • 自定义响应的字段可根据业务需求自由增减,比如添加通知详情、用户信息等

内容的提问来源于stack exchange,提问作者Kyle Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:40:20