我有2个型号First
和Second
,其FK从Second
到First
。我为2类创建了一个表单,并为Second
创建了一个内联表单集。在模板上,我手动设计了表单,并使用jQuery添加了Second
的动态表单。
在UpdateView上,表单已正确填充,但是当我提交表单时,所有Second
实例都是使用新ID而不是更新它们重新创建的。我仔细检查了HTML上是否有具有正确ID的name = PREFIX-FORM_COUNT-id
,但似乎Django忽略了它。
我正在使用Django 2.2.12和Python 3.6
我在这里做了:
models.py
class First(models.Model):
name = models.CharField(max_length=100, null=False)
class Second(models.Model):
first= models.ForeignKey(First, null=False, on_delete=models.CASCADE)
number= models.FloatField(null=False, default=0)
form.py
class FirstForm(forms.ModelForm):
class Meta:
model = First
fields = "__all__"
class SecondForm(forms.ModelForm):
class Meta:
model = Second
fields = "__all__"
SecondsFormset = inlineformset_factory(First, Second, SecondForm)
view.py
class FirstUpdateView(UpdateView):
template_name = "first.html"
model = First
form_class = FirstForm
context_object_name = "first_obj"
def get_success_url(self):
return reverse(...)
def forms_valid(self, first, seconds):
try:
first.save()
seconds.save()
messages.success(self.request, "OK!")
except DatabaseError as err:
print(err)
messages.error(self.request, "Ooops!")
return HttpResponseRedirect(self.get_success_url())
def post(self, request, *args, **kwargs):
first_form = FirstForm(request.POST, instance=self.get_object())
second_forms = SecondsFormset(request.POST, instance=self.get_object(), prefix="second")
if first_form .is_valid() and second_forms.is_valid():
return self.forms_valid(first_form , second_forms)
...
。html (仅基本标签)
<form method="post">
{% csrf_token %}
<input type="text" id="name" value="{{ first_obj.name }}" name="name" required>
<input type="hidden" name="second-TOTAL_FORMS" value="0" id="second-TOTAL_FORMS">
<input type="hidden" name="second-INITIAL_FORMS" value="0" id="second-INITIAL_FORMS">
<input type="hidden" name="second-MIN_NUM_FORMS" value="0" id="second-MIN_NUM_FORMS">
<div id="seconds_container">
{% for s in first_obj.second_set.all %}
<input type="hidden" name="second-{{forloop.counter0}}-id" value="{{s.pk}}">
<input type="hidden" name="second-{{forloop.counter0}}-first" value="{{first_obj.pk}}">
<input type="number" min="0" max="10" step="1" value="{{s.number}}" name="second-{{forloop.counter0}}-number" required>
{% endfor %}
</div>
<button class="btn btn-success" type="submit">Update</button>
</form>
我检查了Django如何创建表单,它将仅在其上添加DELETE复选框,但所有其他信息均正确存储在表单集中。当我执行.save()
时,它将在db上创建新的Second元素,而不是更改它们。我想念什么?
我解决了!我将TOTAL_FORMS
和INITIAL_FORMS
设置为错误的值。从Django的文档中:
total_form_count返回此表单集中的表单总数。 initial_form_count返回表单集中预先填写的表单数,还用于确定需要多少个表单。您可能永远不需要重写这两种方法,因此请确保在执行此操作之前先了解它们的作用。
所以正确的使用方式是:
在视图中:
在HTML中:
TOTAL_FORMS
,并在需要添加/删除行的情况下对其进行动态更改;INITIAL_FORMS
的行数已填满(编辑/删除),请不要更改;DELETE
复选框,而不是删除整个行;