点击提交按钮触发as_crispy_field无效字段错误的排查与解决
Alright, let's dig into your issues and fix that annoying as_crispy_field got passed an invalid or inexistent field error first, then tackle the follow-up problems you might hit with the next template.
1. Fix the invalid field definition in ModelCreateDescriptionForm
The root cause of your initial error is a mistake in how you defined the description field. You used forms.Textarea() directly as the field type—but Textarea is a widget, not a form field. Crispy Forms can't recognize this "pseudo-field" when you try to render it with |as_crispy_field.
Here's the corrected form code:
class ModelCreateDescriptionForm(forms.ModelForm): name = forms.CharField(max_length=100) # 修正:用CharField + Textarea widget替代直接赋值Textarea description = forms.CharField(widget=forms.Textarea()) model_type = forms.ChoiceField( widget=forms.Select, choices=MODEL_TYPE_CHOICES, ) def __init__(self, project_id=1, *args, **kwargs): super(ModelCreateDescriptionForm, self).__init__(*args, **kwargs) self.fields['model_type'].choices = MODEL_TYPE_CHOICES self.fields['model_type'].required = True class Meta: model = Model fields = ['name', 'description', 'model_type']
2. Pass a valid form instance (not a model instance) to the next template
After saving your model in the modelCreationDescription view, you're passing formDescription (a Model instance) to the modelSetTargetFeatures.html template. But the template expects a ModelSetTargetFeaturesForm instance to render crispy fields—this will trigger the same invalid field error if left unaddressed.
Update the POST branch return logic:
# 在modelCreationDescription视图的POST分支,保存完模型后: if form.is_valid(): formDescription = form.save(commit=False) try: formDescription.project = project formDescription.save() messages.success(request, f'Model description successfully created') # 初始化目标特征表单,传入正确的project_id参数 target_form = ModelSetTargetFeaturesForm(project_id=formDescription.project.id) return render(request, 'models/pred_steps/modelSetTargetFeatures.html', { 'form': target_form, 'model': formDescription, 'project': project }) except Exception as e: messages.warning(request, f'Something wrong! {str(e)}') return redirect('all-model-listview')
3. Fix form initialization and project retrieval in modelSetTargetFeatures view
You have two critical issues here:
- You're passing
model=pktoModelSetTargetFeaturesFormin the GET branch, but the form's__init__expects aproject_idparameter. - The code to fetch the project is unnecessarily complex (and error-prone).
Here's the corrected view code:
def modelSetTargetFeatures(request, **kwargs): pk = kwargs.get('pk') model = Model.objects.get(id=pk) # 修正:直接从关联的model获取project,无需额外查询 project = model.project context = {'model': model, 'project': project} if request.method == 'POST': form = ModelSetTargetFeaturesForm(project.id, request.POST) if form.is_valid(): formTargetFeatures = form.save(commit=False) formTargetFeatures.save() messages.success(request, f'Model target features saved successfully') # 这里记得后续也要传递正确的表单实例到下一个模板 return render(request, 'models/pred_steps/modelFeaturesSelection.html', { 'form': # 初始化对应的特征选择表单实例, 'model': formTargetFeatures, 'project': project }) else: # 修正:传入正确的project_id参数 form = ModelSetTargetFeaturesForm(project_id=project.id) context.update({ 'form': form, 'create_model_description': True, }) return render(request, 'models/pred_steps/modelSetTargetFeatures.html', context)
4. Bonus: Clean up redundant POST handling code
You're manually fetching values from request.POST and reassigning them to the model instance—this is redundant because form.save(commit=False) already populates the model with valid form data. Removing this redundant code reduces the chance of bugs:
# 移除这些手动赋值的代码: # name = request.POST.get(u'name') # description = request.POST.get(u'description') # model_type = request.POST.get(u'model_type') # ... # formDescription.name = name # formDescription.description = description # formDescription.model_type = model_type
内容的提问来源于stack exchange,提问作者dJudge

