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

DRF中如何让ViewSet返回Wallet关联的BudgetEntry收支数据?

问题

我开发了一个DRF应用,其中一个WalletInstance(钱包)可关联多条BudgetEntry(收支记录)。调用ViewSet接口时,返回数据格式如下:

[
    {
        "id": "d458196e-49f1-42db-8bc2-ee1dba438953",
        "owner": 1,
        "viewable": [],
        "entry": []
    }
]

目前entry字段为空数组,请问如何获取并展示该字段的具体内容?


相关模型代码

class Category(models.Model):
    name = models.CharField(max_length=20, unique=True)

    def __str__(self):
        return self.name

class BudgetEntry(models.Model):
    STATE= [
        ('income','income'),
        ('expenses','expenses'),
    ]
    amount = models.IntegerField()
    entry_type = models.CharField(max_length=15, choices=STATE, null=True)
    entry_category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)

class WalletInstance(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
    viewable = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='can_view', blank=True)
    entry = models.ManyToManyField(BudgetEntry, related_name='BudgetEntry', blank=True)

Serializers.py代码

class BudgetEntrySerializer(serializers.ModelSerializer):
    
    class Meta:
        model = BudgetEntry
        fields = '__all__'

class WalletInstanceSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.id')
    class Meta:
        model = WalletInstance
        fields = '__all__'

Views.py代码

class WalletViewset(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = WalletInstanceSerializer

    def get_queryset(self):
        user_id = self.request.user.id

        available = WalletInstance.objects.filter(
            Q(owner=user_id) 
        )
        return available

解决方案

1. 修改序列化器,嵌套收支记录序列化逻辑

当前WalletInstanceSerializer中,entry字段默认仅返回关联对象的ID列表。要展示完整的收支记录内容,需在序列化器中嵌套BudgetEntrySerializer:

修改WalletInstanceSerializer代码:

class WalletInstanceSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.id')
    # 嵌套BudgetEntrySerializer,many=True适配多对多关系
    entry = BudgetEntrySerializer(many=True, read_only=True)
    
    class Meta:
        model = WalletInstance
        fields = '__all__'

2. 优化查询避免N+1性能问题

直接嵌套序列化器会导致每个WalletInstance单独查询一次entry数据,引发N+1查询问题。可在get_queryset中通过prefetch_related预加载关联数据:

修改WalletViewset的get_queryset方法:

from django.db.models import Q

class WalletViewset(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = WalletInstanceSerializer

    def get_queryset(self):
        user_id = self.request.user.id

        available = WalletInstance.objects.filter(
            Q(owner=user_id) 
        ).prefetch_related('entry')  # 预加载entry关联数据
        return available

验证效果

修改完成后重新调用接口,entry字段会展示每条收支记录的完整信息,示例返回格式如下:

[
    {
        "id": "d458196e-49f1-42db-8bc2-ee1dba438953",
        "owner": 1,
        "viewable": [],
        "entry": [
            {
                "id": 1,
                "amount": 1000,
                "entry_type": "income",
                "entry_category": 1
            },
            {
                "id": 2,
                "amount": 500,
                "entry_type": "expenses",
                "entry_category": 2
            }
        ]
    }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 10:33:46