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
相关产品推荐
相关产品推荐

