Django递归模型部署Heroku出现core_menuoption关系不存在错误如何解决
根本原因
你的问题和递归外键没有关系,报错是模块导入阶段提前执行了数据库查询导致的:
从报错栈可以看到,你在执行migrate命令时,Django会先加载项目的URL配置,进而导入MenuOptionForm类,而你在表单的Meta类的widget定义里直接写了choices=[(m, m) for m in MenuOption.objects.all()],这段代码会在导入表单类的瞬间就执行数据库查询,此时migrate命令还没完成表结构创建,自然会报core_menuoption表不存在的错误。
本地运行正常是因为你本地的数据库表已经提前创建完成,导入阶段的查询可以正常返回结果。
可行解决方案
方案1(最推荐,无冗余代码)
直接删除widget中的自定义choices参数即可。Django的ModelForm针对外键字段默认会使用ModelChoiceField,会自动在表单实例化阶段动态拉取对应模型的所有数据作为选项,不需要手动指定choices:
class MenuOptionForm(forms.ModelForm): class Meta: model = MenuOption fields = ('parent', 'title') widgets = { # 删掉多余的choices参数 'parent': forms.Select(attrs={'class': 'form-control mb-1'}), # 顺便修复你代码里少写的引号语法错误 'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'title'}) }
方案2(需要自定义choices时使用)
如果确实需要自定义choices的生成逻辑,把查询逻辑放到表单的__init__方法中,确保只有表单实例化的时候才执行查询,不会在模块导入阶段触发:
class MenuOptionForm(forms.ModelForm): class Meta: model = MenuOption fields = ('parent', 'title') widgets = { 'parent': forms.Select(attrs={'class': 'form-control mb-1'}), 'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'title'}) } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 动态设置choices,仅在表单实例化时执行查询 self.fields['parent'].choices = [(m, m) for m in MenuOption.objects.all()]
方案3(临时应急,不推荐长期使用)
如果暂时不想修改代码,可以临时调整部署流程:先把MenuOptionForm中查询相关的代码注释掉,部署到Heroku完成migrate之后,再恢复代码重新部署一次。但这个方案只是临时解决,后续如果清空数据库或者重新部署还会遇到同样的问题。
内容的提问来源于stack exchange,提问作者D4NieLDev
相关产品推荐
相关产品推荐

