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

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

В соответствии с документами вы можете установить только начальную версию.

Ответы

Ответ 1

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

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

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])

Ответ 2

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

Форма, известная, что она будет собирать дополнительные параметры

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

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 оценивается по частям, проходящим в итерированном параметре. Мы можем перебирать то, что нам нравится, поэтому я использую этот факт для итерации по набору объектов и передачи значения каждого из них в качестве другого начального параметра.

Ответ 3

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

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))

Возможно, это тоже сработает для вас.

Ответ 4

Основываясь на ответе Антони Веннарда, я не уверен, какую версию python/django он использует, но я не мог заставить генератор работать в методе curry. Я сейчас на 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 в "extra" kwarg для formset_factory). Это необходимо для создания в форме набора нескольких форм.