Различные исходные данные для каждой формы в наборе форм Django

Можно ли предварительно заполнить набор форм разными данными для каждой строки? Я хотел бы поместить некоторую информацию в скрытые поля из предыдущего просмотра.

Согласно документам, вы можете установить только начальное значение по всем направлениям.


person cerial    schedule 13.12.2009    source источник


Ответы (5)


Если вы совершили ту же ошибку, что и я, вы немного ошиблись в документации.

Когда я впервые увидел этот пример ...

formset = ArticleFormSet(initial=[
 {'title': 'Django is now open source',
  'pub_date': datetime.date.today(),}
])

Я предположил, что каждой форме предоставляется один и тот же набор исходных данных на основе словаря.

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

Чтобы установить разные начальные значения для каждой формы в наборе форм, вам просто нужно передать список словарей, содержащих разные данные.

Formset = formset_factory(SomeForm, extra=len(some_objects)
some_formset = FormSet(initial=[{'id': x.id} for x in some_objects])
person Alistair    schedule 06.05.2014
comment
Кажется, это самый простой способ сделать это, и способ, используемый Django по умолчанию, и указывает на то самое заблуждение, которое было у OP. Должен быть главный ответ. - person ACPrice; 07.07.2015
comment
Обратите внимание, что это сделает ArticleFormSet несвязанной формой, так как начальные значения перезапишут значения, возвращаемые из набора запросов статьи. - person Myer; 04.10.2016
comment
@Alistair, Вы тут ошиблись, это {'id': x.id} вместо {'id': 'x.id'} - person RendoJack; 15.03.2018
comment
Отличный способ сделать это! Спасибо! - person Ron; 06.04.2018
comment
Замечательное решение! Спасибо! Важно! Я проверил, что в formset_factory вы указываете точную длину дополнительных форм. - person Vyachez; 28.08.2019
comment
Я пробовал это и думаю, что дополнительный должен быть установлен на 0, если вы не хотите, чтобы отображались лишние пустые формы. - person mfnx; 03.06.2020

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

Форма осведомлена о дополнительных параметрах

Пример из связанного вопроса:

def __init__(self, *args, **kwargs):
    someeobject = kwargs.pop('someobject')
    super(ServiceForm, self).__init__(*args, **kwargs)
    self.fields["somefield"].queryset = ServiceOption.objects.filter(
                                                           somem2mrel=someobject)

Или вы можете заменить последний код на

    self.fields["somefield"].initial = someobject

Напрямую и работает.

Настройка инициализации каррированной формы:

formset = formset_factory(Someform, extra=3)
formset.form = staticmethod(curry(someform, somem2mrel=someobject))

Это позволяет вам передавать настраиваемые параметры формы. Теперь вам нужно:

Генератор для получения различных начальных параметров

Я использую это:

def ItemGenerator(Item):
    i = 0
    while i < len(Item):
        yield Item[i]
        i += 1

Теперь я могу сделать это:

iterdefs = ItemGenerator(ListofItems) # pass the different parameters 
                                      # as an object here
formset.form = staticmethod(curry(someform, somem2mrel=iterdefs.next()))

Вуаля. Каждая оценка метода form оценивается частями, передающими повторяющийся параметр. Мы можем перебирать то, что нам нравится, поэтому я использую этот факт для перебора набора объектов и передачи значения каждого из них в качестве другого начального параметра.

person Community    schedule 25.04.2011
comment
Привет! Я думаю, ваш ответ может решить проблему, которую я рассматриваю в этом вопросе stackoverflow.com/questions/6123278/. Но на самом деле я не очень понимаю, что происходит - person psoares; 25.05.2011
comment
Я пробовал использовать этот подход, но не могу заставить итератор выполнять итерацию при каждом вызове. Мой код: DecorationFileFormSet.form = staticmethod(curry(DecorationFileForm, filetype=counter.next())) создает формы, в которых атрибут filetype каждый раз равен 1. counter является экземпляром itertools.count(1) - person Jamie Forrest; 18.04.2012
comment
У кого-нибудь уже есть решение? Генератор у меня тоже не работает (вообще не повторяется). - person wgx731; 11.07.2013
comment
То же самое и здесь. Генератор не выполняет итерацию по .next (). Есть ли люди, для которых этот ответ ДЕЙСТВИТЕЛЬНО работал? - person ACPrice; 08.07.2015

Основываясь на ответе Энтони Веннарда, я не уверен, какую версию python / django он использует, но мне также не удалось заставить генератор работать в методе карри. В настоящее время я использую python2.7.3 и django1.5.1. Вместо использования настраиваемого генератора я закончил тем, что использовал встроенный iter() в списке вещей для создания итератора и передачи самого итератора в метод curry и вызова next() для него в Form __init__(). Вот мое решение:

# Build the Formset:
my_iterator = iter(my_list_of_things) # Each list item will correspond to a form.
Formset = formset_factory(MyForm, extra=len(my_list_of_things))
Formset.form = staticmethod(curry(MyForm, item_iterator=my_iterator))

И в виде:

# forms.py
class MyForm(forms.Form):
    def __init__(self, *args, **kwargs):
        # Calling next() on the iterator/generator here:
        list_item = kwargs.pop('item_iterator').next()

        # Now you can assign whatever you passed in to an attribute
        # on one of the form elements.
        self.fields['my_field'].initial = list_item

Некоторые ключевые моменты, которые я обнаружил, заключались в том, что вам нужно либо указать `` дополнительное '' значение в formset_factory, либо использовать initial kwarg в наборе форм, чтобы указать список, который соответствует списку, который вы передаете итератору (в примере выше я передаю len() списка my_list_of_things в 'дополнительный' kwarg в formset_factory). Это необходимо для фактического создания нескольких форм в наборе форм.

person emispowder    schedule 17.09.2013

У меня возникла эта проблема, и я сделал новый виджет:

from django.forms.widgets import Select
from django.utils.safestring import mark_safe
class PrepolutatedSelect(Select):
    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = ''
        if value == '':
            value = int(name.split('-')[1])+1
        final_attrs = self.build_attrs(attrs, name=name)
        output = [u'<select%s>' % flatatt(final_attrs)]
        options = self.render_options(choices, [value])
        if options:
            output.append(options)
        output.append('</select>')
        return mark_safe(u'\n'.join(output))

Может быть, это сработает и для вас.

person diegueus9    schedule 13.12.2009
comment
У меня проблема, аналогичная OP. Я пытаюсь создать набор форм с несколькими формами, каждая из которых имеет собственный уникальный набор параметров для элемента выбора (т. Е. Вариантов). Я не совсем понимаю, как это решение поможет. Я что-то упускаю? - person ACPrice; 08.07.2015

formset = BookFormset(request.GET or None,initial=[{'formfield1': x.modelfield_name1,'formfield2':x.modelfield_name2} for x in model])

formfield1, formfield2 - названия полей формы.

имя_поля_модели1, имя_поля_модели2 - имена модальных полей.

модель - это имя вашего модального класса в файле models.py.

BookFormset - это форма или имя набора форм, которое определено в вашем файле forms.py

person sreekanth    schedule 25.06.2021