我对django表单有一个非常奇怪的问题,我显示一个包含额外formset的表单,以便用户也可以同时提交外键关系的数据。
模板始终显示原始模型的表单和第二个模型的一个表单。
我现在想要提交两个表格而不填写第二个表格中的任何内容。 在第一次提交时,seond表单不会验证并重新显示页面,但在第二次提交时,第二个表单是有效的!即使如此,POST数据也是相同的。 怎么可能呢?
或许我这样做完全错了,你怎么能辨别出用户是否填写了表单中的任何内容,或者他是否填写了无效的内容?
这里的模型:
class Software(models.Model):
creation_date = models.DateTimeField(default=datetime.now)
creator = models.ForeignKey(User)
version = models.CharField(max_length=300, unique=True, editable=False)
major_version = models.IntegerField()
minor_version = models.IntegerField()
[...]
def save(self, **kwargs):
"""
This updates the version string to the combined representation.
"""
self.version = Software.combine_version_string (self.major_version, self.minor_version)
super(Software, self).save(**kwargs)
class SoftwarePatch(models.Model):
file = models.FileField(upload_to='software_patches')
file_name = models.CharField(max_length=255, editable=False)
file_date = models.DateTimeField(default=datetime.now)
upload_date = models.DateTimeField(default=datetime.now)
software = models.ForeignKey('Software', related_name='patches')
firmware_patch = models.BooleanField(default=True)
target_path = models.CharField(max_length=255, blank=True)
class Meta:
unique_together = ('software', 'file_name')
verbose_name_plural = "software patches"
def __unicode__(self):
return self.file_name
def clean(self):
if self.file and not self.file_name:
self.file_name = self.file.file.name
这是我的表格:
SoftwarePatchFormSet = inlineformset_factory(Software,
SoftwarePatch,
extra=1)
class SoftwareForm(forms.ModelForm):
"""
A simple form for creating a new software.
"""
class Meta:
model = Software
最后我的观点功能:
def software_add(request, software_id=None):
if software_id == None:
software = Software()
else:
software = Software.objects.get(id=software_id)
if request.POST:
form = SoftwareForm(request.POST, instance=software)
if form.is_valid():
software = form.save(commit=False)
softwarepatch_formset = SoftwarePatchFormSet(request.POST, request.FILES, instance=software)
if softwarepatch_formset.is_valid():
software = form.save()
softwarepatch_formset.save()
# Redirect, in case of a popup close it
if request.POST.has_key("_popup"):
pk_value = software._get_pk_val()
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(pk_value), escape(software)))
if 'next' in request.POST:
return HttpResponseRedirect(request.POST['next'])
else:
return HttpResponseRedirect(reverse('index'))
else:
form = SoftwareForm(instance=software)
softwarepatch_formset = SoftwarePatchFormSet(instance=software)
is_popup = request.GET.has_key("_popup") or request.POST.has_key("_popup")
return render_to_response(
'main/software_edit.html',
{'form': form,
'softwarepatch_formset': softwarepatch_formset,
'add': True,
'is_popup': is_popup,
},
context_instance = RequestContext(request)
)
答案 0 :(得分:1)
首先,只有在为现有对象(即DB中已有对象)创建表单/表单集时,才应设置实例参数。例如,如果software_id = None
并且它是GET请求,则应该form = SoftwareForm()
。
此外,在执行software = form.save(commit=False)
后,您应该software.save()
而不是software = form.save()
。 [我认为这不是一个真正的问题,只是你正在重做一次保存]。请注意,如果您在软件模型中有ManyToManyField
,那么您需要在form.save_m2m()
之后software = form.save()
进行操作。
这是我认为你应该拥有的:
def software_add(request, software_id=None):
if request.POST:
if software_id:
software = Software.objects.get(id=software_id)
form = SoftwareForm(request.POST, instance=software)
else:
form = SoftwareForm(request.POST)
if form.is_valid():
software = form.save(commit=False)
softwarepatch_formset = SoftwarePatchFormSet(request.POST, request.FILES, instance=software)
if softwarepatch_formset.is_valid():
software.save()
softwarepatch_formset.save()
# Redirect, in case of a popup close it
if request.POST.has_key("_popup"):
pk_value = software._get_pk_val()
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(pk_value), escape(software)))
if 'next' in request.POST:
return HttpResponseRedirect(request.POST['next'])
else:
return HttpResponseRedirect(reverse('index'))
else:
softwarepatch_formset = SoftwarePatchFormSet(request.POST, request.FILES)
else:
if software_id:
software = Software.objects.get(id=software_id)
form = SoftwareForm(instance=software)
softwarepatch_formset = SoftwarePatchFormSet(instance=software)
else:
form = SoftwareForm()
softwarepatch_formset = SoftwarePatchFormSet()
is_popup = request.GET.has_key("_popup") or request.POST.has_key("_popup")
return render_to_response(
'main/software_edit.html',
{'form': form,
'softwarepatch_formset': softwarepatch_formset,
'add': True,
'is_popup': is_popup,
},
context_instance = RequestContext(request)
)
答案 1 :(得分:0)
好的,我终于找到了问题!
我有以下模型字段:file_date = models.DateTimeField(default = datetime.now)
这将innital-file-date设置为这样的值:u'2011-10-18 08:14:30.242000' 通过html小部件呈现后,值将为:u'2011-10-18 08:14:30' 因此,django会认为表格已经改变,因此无法保存。
在第二次加载时,django会自动将截断值设置为initial-file-date,然后不会更改任何内容,并且保存按预期工作。
所以现在我只需要弄清楚要使用什么而不是datetime.now。我想出来之后我会更新这篇文章。