Django FormWizard с динамическими формами - PullRequest
6 голосов
/ 11 декабря 2008

Я хочу реализовать простой 2-компонентный FormWizard. Форма 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 правильным способом для этого? Если это так, как метод Form __init__ может получить доступ к объекту пользователя из HTTP-запроса?

Ответы [ 5 ]

4 голосов
/ 01 февраля 2011

Когда я пытался понять 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 декабря 2008

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

0 голосов
/ 03 мая 2010

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

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

0 голосов
/ 12 марта 2009

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

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

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

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

0 голосов
/ 11 декабря 2008

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

Во-первых, яма FormWizard.

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

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

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

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

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

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

...