Подтвердить что ты не робот

Django formsets: сделать сначала необходимо?

Эти фигуры демонстрируют совершенно противоположное поведение, которое я хочу.

Мой вид настроен следующим образом:

def post(request): # TODO: handle vehicle formset
    VehicleFormSetFactory = formset_factory(VehicleForm, extra=1)
    if request.POST:
        vehicles_formset = VehicleFormSetFactory(request.POST)
    else:
        vehicles_formset = VehicleFormSetFactory()

И мой шаблон выглядит так:

    <div id="vehicle_forms">
        {{ vehicles_formset.management_form }}
        {% for form in vehicles_formset.forms %}
            <h4>Vehicle {{forloop.counter}}</h4>
            <table>
                {% include "form.html" %}
            </table>
        {% endfor %}
    </div>

Таким образом, он изначально генерирует только 1 форму, как я хочу. Но я хочу, чтобы одна форма была необходима!

Когда я динамически добавляю пустые формы с помощью JavaScript и vehicles_formset.empty_form, требуются все эти дополнительные формы, чего я не хочу.

Из документов:

Набор форм достаточно умен, чтобы игнорировать дополнительные формы, которые не были изменены.

Это поведение, которое показывает первая форма (не то, что я хочу), но не поведение, которое проявляют дополнительные формы (чего я хочу).

Есть ли какой-нибудь атрибут, который я могу изменить, чтобы хотя бы сделать одну форму?

4b9b3361

Ответ 1

Нашел лучшее решение:

class RequiredFormSet(BaseFormSet):
    def __init__(self, *args, **kwargs):
        super(RequiredFormSet, self).__init__(*args, **kwargs)
        for form in self.forms:
            form.empty_permitted = False

Затем создайте свой набор форм следующим образом:

MyFormSet = formset_factory(MyForm, formset=RequiredFormSet)

Я действительно не знаю, почему это был не вариант для начала... но, что угодно. Мне потребовалось всего несколько часов жизни, чтобы понять.

Это сделает все необходимые формы. Вы можете сделать только первый, требуемый установкой self.forms[0].empty_permitted в False.

Ответ 3

Ну... это делает первую форму необходимой.

class RequiredFormSet(BaseFormSet):
    def clean(self):
        if any(self.errors):
            return
        if not self.forms[0].has_changed():
            raise forms.ValidationError('Please add at least one vehicle.') 

Только "проблема" заключается в том, что если существует 0 форм, то метод clean, похоже, вообще не вызван, поэтому я не знаю, как проверить, есть ли 0. Действительно... это никогда не должно произойти (за исключением того, что у моего JS есть ошибка, позволяющая удалить все формы).

Ответ 4

О, я думаю, что вижу. Попробуйте следующее:

from django.forms.formsets import BaseFormSet, formset_factory
class OneExtraRequiredFormSet(BaseFormSet):
    def initial_form_count(self):
        return max(super(OneExtraRequiredFormSet,self).initial_form_count() - 1,0)

VehicleFormSetFactory = formset_factory(VehicleForm, formset=OneExtraRequiredFormSet, extra=1)

== Оригинальный ответ ниже ==

Когда вы говорите "хотя бы сделать одну форму необходимой", я предполагаю, что вы имеете в виду "сделать только одну дополнительную форму, независимо от того, сколько было добавлено через javascript".

Вам нужно будет иметь скрытый ввод на своей странице, который содержит количество форм, которые были добавлены через javascript, а затем использовать это число, минус 1, в качестве значения для передачи в качестве атрибута extra для ваших форм конструктор.