DRF导入API JSON数据至数据库时遇字段非空错误排查
问题分析与解决方案
没错,这本质是数据结构解析错误,不是字段格式问题——你没有正确定位到外部API返回的实际题目数据节点,导致所有字段都提取到None,触发了序列化器的非空校验错误。
问题根源
看你打印的data输出和API返回结构:
{'response_code': 0, 'results': [{'category': 'General Knowledge', ...}]}
实际的题目数据是嵌套在results数组的第一个元素里的,但你的代码直接从顶层data对象提取字段(比如data.get('category')),而顶层对象根本没有这些键,所以所有字段都拿到了None,自然通不过models.py里定义的非空约束。
修复步骤
1. 修正数据提取路径
首先要从results数组中取出目标题目对象,再从中提取字段:
@api_view(['POST']) def opendb(request): data = requests.get(url=request.data['url']).json() # 取出results数组里的第一个题目对象 question_item = data['results'][0] QuestionData = { "category": question_item.get('category'), "type": question_item.get('type'), "difficulty": question_item.get('difficulty'), "question": question_item.get('question'), "answer": question_item.get('correct_answer'), "options": question_item.get('incorrect_answers'), } # 后续代码...
2. 处理关联模型的序列化问题
这一步很关键:你的Question模型里有多个关联字段(category是ForeignKey,options/answer是关联Options的关系),直接传字符串是无法通过ModelSerializer验证的,需要额外处理:
假设你的Category模型有一个name字段,Options模型有一个text字段,你需要:
- 先获取或创建对应的
Category实例 - 创建所有选项(包括正确答案)的
Options实例 - 再关联到
Question对象
修改后的完整视图代码示例:
@api_view(['POST']) def opendb(request): data = requests.get(url=request.data['url']).json() question_item = data['results'][0] # 处理Category:获取或创建对应分类 category, _ = Category.objects.get_or_create(name=question_item['category']) # 处理Options:创建所有选项(正确+错误) options = [] # 添加错误选项 for incorrect in question_item['incorrect_answers']: opt, _ = Options.objects.get_or_create(text=incorrect) options.append(opt) # 添加正确答案选项 answer_opt, _ = Options.objects.get_or_create(text=question_item['correct_answer']) # 构建符合序列化要求的数据 QuestionData = { "category": category.id, # 传入关联对象的ID "type": question_item.get('type'), "difficulty": question_item.get('difficulty'), "question": question_item.get('question'), "answer": answer_opt.id, # 传入正确选项的ID # ManyToMany字段通过主键列表传入 "options": [opt.id for opt in options] } serializer = QuestionSerializer(data=QuestionData) if serializer.is_valid(): serializer.save() return JsonResponse({"data": serializer.data}, status=status.HTTP_200_OK) return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
同时,确保你的QuestionSerializer正确配置了关联字段的序列化方式:
class QuestionSerializer(serializers.ModelSerializer): class Meta: model = Question fields = ['id', 'category', 'question', 'options', 'answer', 'difficulty', 'type'] # 对于ForeignKey和ManyToMany,默认用PrimaryKeyRelatedField,支持传入ID
验证修正效果
修改后,你提取的字段不再是None,同时关联字段也能正确匹配数据库中的实例,就能通过序列化器的校验,成功将数据存入Django数据库了。
内容的提问来源于stack exchange,提问作者Mohammed Adel
相关产品推荐
相关产品推荐

