Django导入API数据时报cannot unpack non-iterable Responses错误如何解决
问题原因及解决方案
直接报错根源
你触发TypeError: cannot unpack non-iterable Responses object的核心原因是:Django ORM的create()方法仅返回创建的模型实例对象,不会返回(实例, 是否创建)的二元组,你用两个变量去接收单个返回值自然会解包失败。
你前5个元素运行正常是因为前5条API返回的Responses字段都是空数组,内层循环根本不会执行,全量数据中存在带Responses的条目,进入内层循环后就会触发错误。
额外逻辑&模型错误
除此之外你的代码还有两个致命问题:
- 外键关系写反:一个问题对应多个回答,外键应该放在
Responses模型中指向GetQuestion_API,而非反过来,否则一个问题只能关联一个回答,不符合你的数据结构。 - 变量未定义风险:如果接口返回的
j['Id']为None,你的Responses_Id变量不会被定义,直接使用会抛NameError。
修复步骤
1. 修改models.py
class GetQuestion_API(models.Model): Question_Id = models.IntegerField(primary_key=True) GroupId = models.IntegerField(default=0) QuestionTitle = models.TextField() GroupName = models.CharField(max_length=500, null=True, blank=True) QuestionChoice = [ ('TEXT', 'TEXT'), ('BUTTON', 'BUTTON'), ('NUMBER', 'NUMBER') ] QuestionType = models.CharField(max_length=50, choices=QuestionChoice, default='TEXT', null=True, blank=True) IsMappingAvailable = models.CharField(max_length=500, null=True, blank=True) BodyRegion = models.CharField(max_length=200, null=True, blank=True) EnableCalculation = models.BooleanField(default=False) # 删掉原来的Responses外键字段 class Responses(models.Model): Answer_Id = models.IntegerField(primary_key=True) # 新增外键关联问题 question = models.ForeignKey(GetQuestion_API, on_delete=models.CASCADE, related_name="response_list", null=True, blank=True) ResponseText1 = models.CharField(max_length=500, null=True, blank=True) ResponseText2 = models.CharField(max_length=500, null=True, blank=True) ResponseText3 = models.CharField(max_length=500, null=True, blank=True) IsDeleted = models.BooleanField(default=False)
修改后执行makemigrations和migrate更新数据库结构。
2. 修改views.py代码
for i in GetQuestion_response: # 先创建问题实例,create方法已经自动保存,不需要后续再调用save() GetQuestion_API_obj = GetQuestion_API.objects.create( Question_Id = i['Id'], GroupId = i['GroupId'], QuestionTitle = i['QuestionTitle'], GroupName = i['GroupName'], QuestionType = i['QuestionType'], IsMappingAvailable = i['IsMappingAvailable'], BodyRegion = i['BodyRegion'], EnableCalculation = i['EnableCalculation'], ) # 遍历当前问题的回答 for j in i['Responses']: # 用get_or_create替代create,避免主键重复报错,同时返回二元组可解包 Responses_obj, created = Responses.objects.get_or_create( Answer_Id = j['Id'], defaults = { "question": GetQuestion_API_obj, "ResponseText1": j.get('ResponseText1'), "ResponseText2": j.get('ResponseText2'), "ResponseText3": j.get('ResponseText3'), "IsDeleted": j.get('IsDeleted', False) } )
优化点说明:
- 用
dict.get()方法取值,不存在的键直接返回None,不需要写多层if判断 get_or_create的defaults参数里放需要更新的字段,避免主键重复时创建失败- 去掉冗余的
save()调用,create和get_or_create已经自动将数据写入数据库 - 不需要手动关联外键,创建Responses时直接传入question参数即可完成关联
内容的提问来源于stack exchange,提问作者Kanchon Gharami
相关产品推荐
相关产品推荐

