Django REST API:如何将ManyToManyField的ID列表转为JSON对象列表?
解决Django REST API中Event多对多字段返回详细信息的问题
当前你的Event模型里event_labels是多对多关联Label,但接口返回的是ID列表字符串,要改成带label_name、alternate_name等字段的对象列表,还得解决django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.错误。下面是一步步的修正方案:
1. 修正序列化器定义错误
你之前的序列化器错继承了models.Model,这完全不对,得继承DRF的serializers.ModelSerializer,而且字段名要和模型里的对应(模型里是event_labels,序列化器里不能瞎写label):
# serializers.py(单独放这个文件,别和models混在一起) from rest_framework import serializers from .models import Event, Label, Image class LabelSerializer(serializers.ModelSerializer): # 如果模型里的字段是grade,但你要返回grade_level,就加个字段映射 grade_level = serializers.CharField(source='grade') class Meta: model = Label fields = ('label_name', 'alternate_name', 'grade_level') class EventSerializer(serializers.ModelSerializer): # 关联字段名必须和Event模型里的一致:event_labels,加上many=True表示多对多 event_labels = LabelSerializer(many=True, read_only=True) class Meta: model = Event fields = ('province', 'event_labels') # 把你需要返回的其他Event字段也加进来 class ImageSerializer(serializers.ModelSerializer): class Meta: model = Image fields = '__all__' # 或者指定你要返回的图片字段 class EventDetailSerializer(serializers.Serializer): Event = EventSerializer() Image = ImageSerializer(many=True) # 一个Event对应多个Image,所以加many=True # 其他需要返回的字段在这里定义
2. 替换业务函数中的默认序列化方法
你之前用的serializers.serialize('json', ...)会返回JSON字符串,还处理不了嵌套的多对多关系,换成自定义序列化器来处理:
def EventDetailGetFunction(user, event_id): context = {} # 用prefetch_related预加载event_labels,减少数据库查询次数 event = Event.objects.prefetch_related('event_labels').get(pk=event_id) images = Image.objects.filter(event=event) # 用自定义序列化器把模型实例转成字典 event_serializer = EventSerializer(event) image_serializer = ImageSerializer(images, many=True) context['Event'] = event_serializer.data context['Image'] = image_serializer.data # 其他字段该怎么加就怎么加,保持原来的逻辑 return context
3. 视图中避免手动JSON序列化
DRF的Response会自动帮你把字典转成JSON,你之前手动调用json.dumps会导致返回的是JSON字符串而不是JSON对象,直接传字典就行:
class EventDetailView(APIView): serializer_class = EventDetailSerializer def get(self, request, username, event_id): try: user = CustomUser.objects.get(username=username) except CustomUser.DoesNotExist: return Response({}) # 直接返回空字典,Response自动处理 ctx = EventDetailGetFunction(user, event_id) return Response(ctx) def post(self, request, username, event_id): try: user = CustomUser.objects.get(username=username) except CustomUser.DoesNotExist: return Response({}) ctx = EventDetailPostFunction(user, event_id, None) return Response(ctx)
4. 解决AppRegistryNotReady错误
这个错误大概率是因为你把序列化器放在了models.py里,或者在模型加载前就导入了序列化器。解决方法:
- 序列化器必须单独放在
serializers.py文件里 - 模型字段只能关联模型类,你之前尝试的
event_labels = models.ManyToManyField(LabelSerializer(Label))完全错误,已经改成正确的models.ManyToManyField(Label)了 - 检查项目的导入顺序,确保先加载模型,再加载序列化器
最终返回格式
调整完之后,接口就会返回你想要的格式:
[{ "Event": { "province": "AB", "event_labels": [{ "label_name": "blah", "alternate_name": "blah", "grade_level": "Grade 9" }, { "label_name": "blah", "alternate_name": "blah", "grade_level": "Grade 10" }] }, "Image": [{"<image_field>": "<image_str>"}] }]
内容的提问来源于stack exchange,提问作者ellen
相关产品推荐
相关产品推荐

