Форма Django действительна только после второго запроса
У меня очень странная проблема с формами django, я отображаю форму, которая включает в себя дополнительный набор форм, чтобы пользователь также мог одновременно отправлять данные для связи с внешним ключом.
Шаблон всегда отображает форму для исходной модели и одну форму для второй модели.
Теперь я хочу отправить две формы, не заполняя ничего во второй форме. При первом представлении форма 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)
)
2 ответа
Хорошо, я наконец нашел свою проблему!
У меня есть следующее поле модели: 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 автоматически установит усеченное значение как initial-file-date, после чего ничего не изменится, и сохранение будет работать, как и ожидалось.
Так что теперь мне нужно только выяснить, что использовать вместо datetime.now. Я буду обновлять этот пост, когда я понял это.
Прежде всего, вы должны устанавливать аргумент экземпляра только при создании формы / набора форм для существующего объекта, то есть уже в БД. Так, например, если 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)
)