Django REST中通过序列化器获取ManyToManyField关联值求助
Django多对多关联数据在通用视图中的获取方案
嘿,我刚看到你的问题啦!作为Django老玩家,太懂新手遇到多对多关联数据获取的困惑了😉 别急,咱们一步步来搞定它,正好prefetch_related就是解决这个问题的关键,我给你详细讲讲具体操作:
先确认你的模型结构(参考示例)
首先我假设你的模型大概是这样的,如果有调整可以对应修改:
from django.db import models class Service(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=100) # 示例字段,按你的实际字段调整 class Owner(models.Model): id = models.AutoField(primary_key=True) first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) services = models.ManyToManyField(Service, related_name='owners')
方案1:用Django REST Framework(推荐,输出JSON更省心)
如果你的项目是做API,用DRF会非常方便:
第一步:定义序列化器
序列化器负责把模型数据转成你要的JSON格式:
from rest_framework import serializers class ServiceSerializer(serializers.ModelSerializer): class Meta: model = Service fields = ('id', 'name') # 这里写你需要返回的Service字段 class OwnerSerializer(serializers.ModelSerializer): # 序列化关联的多个Service,many=True表示是多对多关系 services = ServiceSerializer(many=True) class Meta: model = Owner fields = ('id', 'first_name', 'last_name', 'services')
第二步:写通用视图
用ListAPIView这个通用视图,加上prefetch_related预加载关联数据:
from rest_framework.generics import ListAPIView from .models import Owner class OwnerListView(ListAPIView): # 关键!用prefetch_related预加载services,避免N+1查询 queryset = Owner.objects.all().prefetch_related('services') serializer_class = OwnerSerializer
启动项目访问这个视图,就能得到你想要的格式啦,比如:
[ { "id": 1, "first_name": "james", "last_name": "cook", "services": [ {"id": 1, "name": "清洁服务"}, {"id": 2, "name": "维修服务"} ] } ]
方案2:不用DRF,手动构造JSON返回
如果不用DRF,用普通的通用视图也能实现:
from django.http import JsonResponse from django.views.generic import View from .models import Owner class OwnerJsonView(View): def get(self, request): # 同样用prefetch_related预加载services owners = Owner.objects.all().prefetch_related('services') result_data = [] for owner in owners: # 手动构造每个Owner的字典数据 owner_item = { "owner_id": owner.id, "first_name": owner.first_name, "last_name": owner.last_name, "services": [ {"service_id": service.id, "service_name": service.name} for service in owner.services.all() ] } result_data.append(owner_item) return JsonResponse(result_data, safe=False)
重点提醒
prefetch_related是专门用来处理多对多、反向外键这类跨表关联的预加载,能避免循环每个Owner时都查询一次Services的性能问题(也就是常说的N+1查询)。- 如果你需要返回Service的其他字段,直接在构造字典或者序列化器里添加对应的字段名就行。
内容的提问来源于stack exchange,提问作者Vallabh
相关产品推荐
相关产品推荐

