You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中ModelForm+ModelChoiceField提交AJAX表单报undefined错误求助

解决AJAX提交ModelForm时的undefined错误及ModelChoiceField用法问题

你遇到的问题是:使用AJAX提交包含两个下拉框的ModelForm时,前端弹出undefined错误;调试发现表单数据能正常传到后端,但改用手动输入框就能提交成功,核心问题出在ModelChoiceField的错误使用。

核心原因

ModelChoiceField是Django表单中用于外键关联模型实例的字段,它要求queryset参数必须是模型实例的集合,但你的代码中用了values_list('categorie_lucrare', flat=True),返回的是字符串/值的列表,不是ManoperaRaportareBloc的实例,导致表单验证阶段form.is_valid()直接失败。

同时,视图的错误返回逻辑有缺陷:

  • 当表单验证失败时,返回的JSON里没有error字段,而前端错误处理里直接读取err.error,导致弹出undefined;
  • 最后兜底的返回也把error设为空字符串,进一步加剧了这个问题。

解决方案

1. 修正表单字段类型(关键)

如果RaportProductie模型的categorie_lucrare和subcategorie_lucrare是字符类型字段(而非外键),应该改用ChoiceField,动态从ManoperaRaportareBloc中获取去重后的选项:

# forms.py
from django import forms
from .models import RaportProductie, ManoperaRaportareBloc
import datetime

class RaportProductieForm(forms.ModelForm):   
    data = forms.DateField(initial=datetime.date.today)   
    # 改用ChoiceField,values_list返回(值, 显示文本)的元组,distinct去重
    categorie_lucrare = forms.ChoiceField(
        choices=ManoperaRaportareBloc.objects.values_list('categorie_lucrare', 'categorie_lucrare').distinct()
    )
    subcategorie_lucrare = forms.ChoiceField(
        choices=ManoperaRaportareBloc.objects.values_list('subcategorie_lucrare', 'subcategorie_lucrare').distinct()
    )

    class Meta:
        model = RaportProductie
        fields = ['lucrare', 'data', 'tip', 'subcontractor', 'obiectiv', 'categorie_lucrare', 'subcategorie_lucrare', 'um', 'cantitate', 'valoare_prod']

如果这两个字段是外键关联到ManoperaRaportareBloc,则需要保留ModelChoiceField,但queryset必须直接用模型实例集合:

categorie_lucrare = forms.ModelChoiceField(
    queryset=ManoperaRaportareBloc.objects.all(),
    # 自定义选项显示文本为categorie_lucrare字段值
    label_from_instance=lambda obj: obj.categorie_lucrare
)

2. 优化视图的错误返回逻辑

修改视图,返回表单的具体验证错误,同时修复兜底返回的error字段:

# views.py
from django.http import JsonResponse
from django.core import serializers
from .forms import RaportProductieForm

def raportproductie_create_view(request):
    # 替换已弃用的request.is_ajax(),改用请求头判断AJAX
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest' and request.method == "POST":
        form = RaportProductieForm(request.POST)
        if form.is_valid():
            instance = form.save()
            ser_instance = serializers.serialize('json', [instance])
            return JsonResponse({"instance": ser_instance}, status=200)
        else:
            # 返回表单具体错误,方便调试
            data = {
                'result': 'error',
                'message': '表单验证失败',
                'errors': form.errors.as_json(),
            }
            return JsonResponse(data, status=400)
    # 兜底返回明确的错误信息
    return JsonResponse({"error": "非法请求"}, status=400)

3. 前端错误处理优化

修改AJAX的错误回调,避免读取不存在的字段导致undefined:

// template.html
$("#friend-form").submit(function (e) {
    e.preventDefault();
    var serializedData = $(this).serialize();
    console.log(serializedData)
    $.ajax({
        type: 'POST',
        url: "{% url 'proiecte:raportprod-create' %}",
        data: serializedData,
        success: function (response) {             
            var instance = JSON.parse(response["instance"]);
            var fields = instance[0]["fields"];                
            $("#table-ajax tbody").prepend("<tr><td>"+fields.data+"</td><td>"+fields.tip+"</td><td>"+fields.subcontractor+"</td><td>"+fields.obiectiv+"</td><td>"+fields.categorie_lucrare+"</td><td>"+fields.subcategorie_lucrare+"</td><td>"+fields.um+"</td><td>"+fields.cantitate+"</td><td>"+fields.valoare_prod+"</td></tr>")
        },
        error: function (xhr, status, error) {
            var err = JSON.parse(xhr.responseText);
            // 优先显示具体错误,没有则显示默认信息
            alert(err.errors || err.message || '提交失败,请检查表单');
        }
    })
})

内容的提问来源于stack exchange,提问作者Kertz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 12:05:22