Django执行makemigrations报no such table: store_product错误如何解决
问题根因
你排查的结论完全正确,Django 加载应用模块时会执行表单类的类属性代码,你直接在ChoiceField的choices参数中执行Product.objects.all()查询,运行makemigrations时Django会提前加载所有应用模块,此时数据库还没创建store_product表,就会触发报错。本地环境正常是因为本地已经提前创建过对应表,新环境无表就触发了问题。
解决方案
这里提供两种可行方案,优先选择第一种:
方案1:改用ModelChoiceField(推荐)
Django原生提供的ModelChoiceField就是专门用来实现从数据库模型生成下拉选项的场景,它的查询不会在类定义阶段执行,只会在表单实例化时动态加载:
class ItemSelectForm(forms.Form): # 替换原来的ChoiceField定义 p_name = forms.ModelChoiceField( label='Select Product', queryset=Product.objects.all(), to_field_name='product_code' # 指定提交时的值为product_code,和原来的逻辑对齐 ) qty = forms.IntegerField() # 后续clean_qty方法不用改,原有逻辑保持不变即可 def clean_qty(self): data = self.cleaned_data['qty'] product_code = self.cleaned_data['p_name'] product = Product.objects.get(product_code = product_code) if data > product.current_stock: raise forms.ValidationError(('Insufficient Stock'), code='ins_stock') return data
方案2:把choices加载逻辑放到表单__init__方法中
如果你坚持要用ChoiceField,可以把数据库查询的逻辑移到表单实例化阶段执行,避免模块加载时就触发查询:
class ItemSelectForm(forms.Form): # 类定义阶段只声明字段,不执行查询 p_name = forms.ChoiceField(label='Select Product', choices=[]) qty = forms.IntegerField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 只有实例化表单时才执行数据库查询加载选项 self.fields['p_name'].choices = [(obj.product_code, obj.name) for obj in Product.objects.all()] # clean_qty方法保持原有逻辑不变 def clean_qty(self): data = self.cleaned_data['qty'] product_code = self.cleaned_data['p_name'] product = Product.objects.get(product_code = product_code) if data > product.current_stock: raise forms.ValidationError(('Insufficient Stock'), code='ins_stock') return data
后续操作
改完代码后,删除应用下migrations目录中之前生成失败的迁移文件(保留__init__.py),再重新执行python manage.py makemigrations和python manage.py migrate即可正常运行。
内容的提问来源于stack exchange,提问作者Rubel Biswas
相关产品推荐
相关产品推荐

