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

Django表单无法保存排查:无报错但数据无法存储

Django表单无法保存数据的排查与修复

问题描述

尝试保存Django表单,但数据无法存储。程序无报错,执行print(form.errors)也无输出。相同代码在其他页面可正常运行,怀疑存在拼写错误但未找到。模板包含地址自动补全功能,最初以为是自动补全未返回所有字段数据,但手动输入也无效。试过包含和不包含is_ajax的判断,结果一致。


相关代码

models.py

class Venue(models.Model):
    name = models.CharField(verbose_name="Name",max_length=100, null=True, blank=True)
    address = models.CharField(verbose_name="Address",max_length=100, null=True, blank=True)
    town = models.CharField(verbose_name="Town",max_length=100, null=True, blank=True)
    county = models.CharField(verbose_name="County",max_length=100, null=True, blank=True)
    post_code = models.CharField(verbose_name="Post Code",max_length=8, null=True, blank=True)
    country_1 = models.CharField(verbose_name="Country1",max_length=100, null=True, blank=True)
    country_2 = models.CharField(verbose_name="Country2",max_length=100, null=True, blank=True)
    longitude = models.CharField(verbose_name="Longitude",max_length=50, null=True, blank=True)
    latitude = models.CharField(verbose_name="Latitude",max_length=50, null=True, blank=True)
    phone = models.CharField(max_length=120)
    web = models.URLField('Website Address')
    email_address = models.EmailField('Venue Email Address')
    
    def __str__(self):
        return str(self.name) if self.name else ''

forms.py

class VenueForm(ModelForm):
    name = forms.CharField(max_length=100, required=True, widget = forms.TextInput(attrs={'id':"name"}))
    address = forms.CharField(max_length=100, widget = forms.TextInput(attrs={'id':"address"}))
    town = forms.CharField(max_length=100, required=True, widget = forms.TextInput(attrs={'id':"town"}))
    county = forms.CharField(max_length=100, required=True, widget = forms.TextInput(attrs={'id':"county"}))
    post_code = forms.CharField(max_length=8, required=True, widget = forms.TextInput(attrs={'id':"post_code"}))
    country_1 = forms.CharField(max_length=40, required=True, widget = forms.TextInput(attrs={'id':"country_1"}))
    country_2 = forms.CharField(max_length=40, required=True, widget = forms.TextInput(attrs={'id':"country_2"}))
    longitude = forms.CharField(max_length=50, required=False, widget = forms.TextInput(attrs={'id':"longitude"}))
    latitude = forms.CharField(max_length=50, required=False, widget = forms.TextInput(attrs={'id':"latitude"}))
    phone = forms.CharField(max_length=120,required=False)
    web = forms.URLField(max_length=120,required=False)
    email_address = forms.CharField(max_length=120, required=False)

    class Meta:
        model = Venue
        fields = ['name', 'address', 'town', 'county', 'post_code','country_1','country_2','longitude','latitude','web', 'phone', 'email_address']

views.py

def google_api_test(request):
    submitted = False
    form = VenueForm()
    if is_ajax(request) and request.method =="POST":
        form = VenueForm(data = request.POST)
        if form.is_valid():
            form.save()
            messages.success(request,("Success!"))
            return redirect('home')
        else :
            print(form.errors)
    context = {
    'form' : form,
    'submitted' : submitted,
    'google_api_key' : settings.GOOGLE_API_KEY,
    'base_country' : settings.BASE_COUNTRY,
    }
    return render(request,"main/google_api_test.html", context)

HTML模板

<div class = "form-group">

         <input id="autocomplete" style ="width: 500px "placeholder="Enter your address">

         <form id="venueform" method="POST" action="">
            {% csrf_token %}
            {{ form|as_crispy_errors }}
            <td class="label">Name (Name)</td>
            {{form.name| as_crispy_field}}
         </br>
            <td class="label">Street Number + Street Name (Address)</td>
            {{form.address| as_crispy_field}}
        </br>
            <td class="label">Town (town)</td>
            {{form.town | as_crispy_field}}
        </br>
            <td class="label">Country(country_1)</td>
            {{form.country_1| as_crispy_field}}
        </br>
            <td class="label">Post Code (post_code)</td>
            {{form.post_code| as_crispy_field}}
        </br>
            <td class="label">Country(country_2)</td>
            {{form.country_2| as_crispy_field}}
        </br>
            <td class="label">Country(longitude)</td>
            {{form.longitude| as_crispy_field}}
        </br>
            <td class="label">Country(latitude)</td>
            {{form.latitude| as_crispy_field}}
        </br>
            <td class="label">phone(phone)</td>
            {{form.phone| as_crispy_field}}
        </br>
            <td class="label">web(web)</td>
            {{form.web| as_crispy_field}}
        </br>
            <td class="label">email_address(email_address)</td>
            {{form.email_address| as_crispy_field}}
        </br>

        <button type="submit" value="Submit" id="profile-btn">Validate</button>
        </form>
    </div>

排查与修复步骤

1. 补全模板中缺失的county字段

HTML模板里没有渲染county字段,但表单中county被设为required=True,提交时缺少该字段会导致表单验证失败。添加以下代码到模板中合适位置:

<td class="label">County (county)</td>
{{form.county| as_crispy_field}}
<br/>

2. 统一模型与表单的必填规则

模型中的phone、web、email_address字段未设置null=True和blank=True,属于数据库必填项,但表单中把这三个字段设为required=False。若提交时这三个字段为空,表单验证会通过,但保存到数据库时会报错。

方案一:修改模型允许字段为空

phone = models.CharField(max_length=120, null=True, blank=True)
web = models.URLField('Website Address', null=True, blank=True)
email_address = models.EmailField('Venue Email Address', null=True, blank=True)

修改后执行数据库迁移:

python manage.py makemigrations
python manage.py migrate

方案二:修改表单强制字段必填

phone = forms.CharField(max_length=120, required=True)
web = forms.URLField(max_length=120, required=True)
email_address = forms.EmailField(max_length=120, required=True)

3. 修正is_ajax判断逻辑

若表单是普通提交(非AJAX),is_ajax(request)会返回False,导致处理分支被跳过,表单未处理提交数据。

临时测试:去掉is_ajax判断

def google_api_test(request):
    submitted = False
    form = VenueForm()
    if request.method == "POST":
        print(request.POST)  # 打印提交数据,排查字段缺失问题
        form = VenueForm(data=request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Success!")
            return redirect('home')
        else:
            print(form.errors)
    context = {
        'form': form,
        'submitted': submitted,
        'google_api_key': settings.GOOGLE_API_KEY,
        'base_country': settings.BASE_COUNTRY,
    }
    return render(request,"main/google_api_test.html", context)

若需AJAX提交:

Django 3.1+已弃用request.is_ajax(),改用请求头判断:

if request.method == "POST" and request.headers.get('X-Requested-With') == 'XMLHttpRequest':
    # 处理AJAX请求逻辑

同时确保前端AJAX请求携带X-Requested-With: XMLHttpRequest头。

4. 验证提交数据完整性

在views中打印request.POST,确认所有必填字段都被正确提交,以此排查字段缺失或拼写错误问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 08:15:29