Укороченная версия: создание динамически нескольких наборов форм сохраняет только то количество наборов форм, которое указано в атрибуте дополнительный, а не столько, сколько я.
Длинная версия: Я делаю свой первый проект с Django, и мне нужно создать CreateView с родительскими и дочерними формами. Мне нужно создать столько вложенных дочерних форм, сколько хочет пользователь, поэтому я создал небольшой код в Javascript, который добавляет / удаляет дочерние формы. Это нормально работает.
Проблема в том, что я могу сохранить только столько форм, сколько я указал в атрибуте дополнительный. Если я скажу «3», будет создано 3 дочерних формы, и я могу сохранить 3 из них, даже если я создам / удаляю дочерние формы. Если я скажу «1», я могу создать 10, но сохраню только 1. Кажется, что в шаблоне чего-то не хватает, но я не знаю что. Вот соответствующий код:
forms.py
class ParentForm(ModelForm):
class Meta:
model = Parent
exclude = ()
class ChildForm(ModelForm):
class Meta:
model = Child
fields = ....
ChildFormSet = inlineformset_factory(Parent, Child, form=ChildForm, can_delete=True, extra=1)
views.py
class ParentCreateView(LoginRequiredMixin, CreateView):
model = Entrada
fields = ...
def get_context_data(self, **kwargs):
data = super(ParentCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['child_form'] = ChildFormSet(self.request.POST)
data['materials'] = Material.objects.all()
else:
data['child_form'] = ChildFormSet()
data['materials'] = Material.objects.all()
return data
def form_valid(self, form):
context = self.get_context_data()
child_form = context['child_form']
with transaction.atomic():
self.object = form.save()
if child_form.is_valid():
child_form.instance = self.object
child_form.field1 = self.object.id
child_form.save()
return super(ParentCreateView, self).form_valid(form)
template.html
<form class = "own-form" action = "" method = "post">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
<h2 class = "text-center text-header"> New Entry</h2>
<div class = "form-group">
{% for field in form.visible_fields %}
<div class = "form-group row">
<div class = "col-4 text-center">{{ field.label_tag }}</div>
<div class = "col-8">{{ field }}</div>
{% if field.help_text %}
<small class = "form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
</div>
<hr>
<div class = "form-group form-material-box row form-0">
<div class = "col-3 text-center">
<label>Total weight: </label>
<input type = "number" id = "kg_0">
</div>
<div class = "col-3 text-center">
<label>Boxes to create: </label>
<input type = "number" id = "num_boxes_0">
</div>
<div class = "col-3 text-center">
<label>Material: </label>
<br>
<select name = "item_id" id = "material_0">
{% for material in materials %}
<option value = "{{ forloop.counter }}">{{ material }}</option>
{% endfor %}
</select>
</div>
<div class = "col-3 text-center">
<button type = "button" id = "create_boxes_0" class = "btn btn-danger">Create</button>
</div>
<!-- Nested forms with desired number of boxes -->
<div id = "nested_forms_0">
<div class = "row" id = "box_0">
{% for bala in bala_form %}
<div class = "col-3 text-center">
<h5>Bala #1: </h4>
</div>
<div class = "col-2 text-center">
{{ bala.kg }}
</div>
<div class = "col-2 text-center" >
{{ bala.material }}
</div>
<div class = "col-2 text-center" >
{{ bala.box_price }}
</div>
<div class = "col-3 text-center">
<button type = "button" id='remove_box_0' class = "btn btn-danger">Remove box</button>
</div>
{% endfor %}
</div>
</div>
</div>
<p>
{{ child_form.management_form }}
<input id = "create" class = "btn btn-secondary btn-lg btn-block btn-option btn-form" type = "submit" value = "Crear" />
</p>
Редактировать:
соответствующий код javascript
// Adds the difference between desired boxes and current boxes
function add_boxes(form_id, total, num){
for (let i = total; i != total+num; i++) {
var element = $('#nested_forms_' + form_id + "> :first-child ").clone().css('display', 'none');
element.appendTo('#nested_forms_' + form_id).show('250');
};
$('#id_child-TOTAL_FORMS').val(num + total);
};
// Removes every unneeded boxes
function remove_boxes(form_id, total){
$('#nested_forms_' + form_id).children().each(function(){
if ($(this).index() >= total) {
$(this).fadeTo(150, 0).slideUp(150, function(){
$(this).remove();
});
}
});
$('#id_child-TOTAL_FORMS').val(total);
}
Что мне не хватает?
Обновлять Я распечатал информацию, переданную Django из шаблона. Похоже, он просто получает пустую форму без какого-либо значения, когда я создаю больше форм дополнительный. Сравнивая различия, когда я создаю 3 формы динамически (слева) и жестко кодирую 3, как показывает значение дополнительный (справа) (bales-materies-primeres - это имя ребенка):
Сделанный. Также я проверил HTML с инспектором, который обновляет значение TOTAL_FORMS.
Похоже, я не получаю контекстные данные формы. Проверьте раздел «обновить» в конце исходного сообщения.
Почему у вас два Child
внутри inlineformset_factory()
?
упс, это была ошибка, когда я менял оригинальные названия моделей. Это должен быть Родитель, Ребенок.
Что bala_form
в шаблоне? Вы установили prefix
, как сказано (ниже) с помощью Дэниел Розман?
Ваш Javascript должен изменить значение поля form-TOTAL_FORMS
в форме управления. См. документация по формам.
Я отредактировал исходное сообщение, добавив соответствующий раздел кода JS, а также проверил, что обновляет значение TOTAL_FORMS.
Вы уверены, что это поле называется child-TOTAL_FORMS
? Я не вижу ничего, что устанавливает префикс набора форм как «дочерний».
Да, как я уже сказал, я проверил HTML с помощью инспектора Chrome. Похоже, я неправильно получаю значения из формы, см. Обновление в OP для получения дополнительной информации.
Покажите свой код javascript для добавления / удаления форм.