Django FormWizard с динамическими формами

Я хочу реализовать простой FormWizard из 2 частей. Форма 1 будет динамически генерироваться примерно так:

class BuyAppleForm(forms.Form):
   creditcard = forms.ChoiceField(widget = forms.RadioSelect)
   type = forms.ChoiceField(widget = forms.RadioSelect)
   def __init__(self,*args, **kwargs):
        user = kwargs['user']
        del kwargs['user']

        super(BuyAppleForm, self).__init__(*args, **kwargs)

        credit_cards = get_credit_cards(user)
        self.fields['creditcard'].choices = [(card.id,str(card)) for card in credit_cards]

        apple_types= get_types_packages()
        self.fields['type'].choices = [(type.id,str(type)) for type in apple_types]

Это будет динамически создавать форму со списками доступных вариантов.

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

Я смог реализовать единственный способ, передав объект request.user в kwargs. Однако с FormWizard я не могу понять это.

Неправильно ли я подхожу к проблеме и не является ли FormWizard правильным способом для этого? Если это так, как __init__метод Form может получить доступ к объекту пользователя из HTTP-запроса?

11.12.2008 04:13:41
5 ОТВЕТОВ
РЕШЕНИЕ

Я не знаю, является ли ответ на собственный вопрос приемлемым поведением в StackOverflow, вот мое решение моей собственной проблемы.

Во-первых, канаву FormWizard.

У меня есть одна форма. Два взгляда: buy_applesиbuy_apples_confirm

Первый вид только обрабатывает GET. Он распечатывает несвязанную форму с действием, чтобы перейти к URL второго вида.

Второе представление проверяет наличие параметра POST с именем «подтверждения». Если он отсутствует (как это не происходит при первой загрузке представления), он:

  1. Настраивает виджет на все поля, чтобы быть HiddenInput
  2. Записывает шаблон, который выдает сводку заказа. Этот шаблон также устанавливает скрытое поле, называемое «подтверждение», равным 1 (хотя это поле не существует в форме)

Когда пользователь нажимает кнопку «купить яблоки», форма отправляется обратно, и buy_apples_confirmпредставление вызывается еще раз. На этот раз присутствует параметр POST, называемый «подтвердить», поэтому мы фактически обрабатываем транзакцию покупки, и пользователь получает свои яблоки.

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

0
11.12.2008 06:18:07

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

4
11.12.2008 12:14:22
Спасибо, что указали на FormPreview. Однако, в моем случае, часть проблемы заключается в передаче дополнительного значения ** kwargs (request.user как «пользователь») в инициатор конструктора Form (необходим для динамической генерации форм), и я не вижу, как это возможно с FormPreview.
Krystian Cybulski 13.12.2008 02:21:23
Я не уверен, поможет ли это (с FormPreview), но что-то, что вы могли бы сделать в приведенном выше коде, - не помещать этот код в метод init . например, x = BuyAppleForm (), затем выполните x.set_choices_for_user (request.user) перед его отображением.
Tom 15.12.2008 03:45:13

Спасибо, Крыс, что ответили на свой вопрос. Помог мне, но я все же получил некоторые замечания.

FormPreview - это не тот путь, который, насколько я знаю, не поддерживает динамические формы. Он опирается на фиксированный класс формы для генерации оттуда. Но мы генерируем динамически здесь с помощью функции. Может быть, FormPreview поддержит это однажды (или уже делает, и я не знаю, как).

Решение Krys, кажется, делает то же самое, что FormPreview. Оставлен только хеш, поэтому пользователь может изменять данные в скрытых полях или вы проверяете это снова ?. Если вы проверите это снова, это не будет следовать за СУХОЙ, потому что вы дублируете проверку (хорошо, может быть в методе многократного использования, так что только незначительное повторение).

Что мне было интересно, как вы настраиваете виджет? Вы дублируете форму с новыми виджетами или есть способ изменить это динамически?

0
12.03.2009 10:43:10

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

что-то похожее на это: http://dw.me/blog/2010/3/18/15/

0
3.05.2010 02:38:48

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

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

Я думаю, что с точки зрения OP, переопределение process_step - это путь. Хитрость заключается в создании формы (или представления) в этом методе, который будет получать данные из первой формы.

Я добавил этот form_setup в мой forms.py в качестве служебной оболочки (думаю, конструктор):

def form_setup(**kwargs):
    def makeform(data, prefix=None, initial=None):
        form = FormLev2(data, prefix, initial)
        for k, v in kwargs.items():
            if k == 'some_list':
                form.fields['some_list'].choices = v
            ...
        return form
    return makeform

Затем переопределите process_step следующим образом:

def process_step(self, request, process, step):
    if step == 1
        if form.is_valid():  #form from step 1
            objs = Table.objects.filter(...) #based on last form 
            self.form_list[1] = form_setup(some_list=[(o.id,o.name) for o in objs])  #(*)
    ...

Таким образом, вы можете динамически изменять form_list (*) в том смысле, что вы изменяете form_list в экземпляре FormWizard, а не сами определения форм. Функция-обертка необходима для этой функции, так как она возвращает функцию, которая будет создавать новый объект Form, который затем используется в FormWizard для вызова с данными для следующей формы, и позволяет использовать данные из предыдущей формы. ,

Редактировать: для комментария Эрика и для уточнения последней части.

Также обратите внимание, что process_step будет вызываться с шагом [0, n] после шага n.

4
11.11.2011 23:59:53
for k, v in kwargsЛиния должна быть for k, v in kwargs.items(). Кроме этого, отличное решение :)
user188041 23.04.2011 10:26:12