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]
Это будет динамически создавать форму со списками доступных вариантов.
Моя вторая форма, я на самом деле не хочу никакой информации. Я просто хочу отобразить экран подтверждения, содержащий информацию о кредитной карте, информацию о яблоке и суммы денег (итого, налог, доставка). Как только пользователь нажмет OK, я хочу начать покупку яблок.
Я смог реализовать единственный способ, передав объект request.user в kwargs. Однако с FormWizard я не могу понять это.
Неправильно ли я подхожу к проблеме и не является ли FormWizard правильным способом для этого? Если это так, как форма __init__
метод доступа к объекту пользователя из запроса HTTP?
5 ответов
Я не знаю, является ли ответ на собственный вопрос приемлемым поведением в Stackru, вот мое решение моей собственной проблемы.
Во-первых, канаву FormWizard.
У меня есть одна форма. Два взгляда: buy_apples
а также buy_apples_confirm
Первый вид только обрабатывает GET. Он распечатывает несвязанную форму с действием, чтобы перейти к URL второго вида.
Второе представление проверяет наличие параметра POST с именем "подтверждения". Если он отсутствует (как это не происходит при первой загрузке представления), он:
- Настраивает виджет на все поля, чтобы быть HiddenInput
- Записывает шаблон, который выдает резюме заказа. Этот шаблон также устанавливает скрытое поле, называемое "подтверждение", равным 1 (хотя это поле не существует в форме)
Когда пользователь щелкает, чтобы купить яблоки, форма отправляется обратно и buy_apples_confirm
представление вызывается еще раз. На этот раз присутствует параметр POST, называемый "подтвердить", поэтому мы фактически обрабатываем транзакцию покупки, и пользователь получает свои яблоки.
Я приветствую любые критические замечания по этому методу или лучшие способы справиться с ситуацией. Я новичок в Django и обнаружил, что есть много разных способов решения проблемы. Я хочу учиться у лучших, хотя.
Я не использовал его, но для описываемой вами ситуации кажется, что вы можете попробовать FormPreview вместо FormWizard. Из документации это звучит как то, что вы ищете.
Когда я пытался выяснить 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.
Как насчет изменения метода вызова, чтобы получить дополнительный параметр?
что-то похожее на это: http://d-w.me/blog/2010/3/18/15/
Спасибо, Крыс, что ответили на свой вопрос. Помог мне, но я все же получил некоторые замечания.
FormPreview - это не тот путь, который, насколько я знаю, не поддерживает динамические формы. Он опирается на фиксированный класс формы для генерации оттуда. Но мы генерируем динамически здесь с помощью функции. Может быть, FormPreview поддержит это однажды (или уже делает, и я не знаю, как).
Решение Krys, похоже, делает то же самое, что и FormPreview. Оставлен только хеш, поэтому пользователь может изменять данные в скрытых полях или вы проверяете это снова? Если вы проверите это снова, это не будет следовать за СУХОЙ, потому что вы дублируете проверку (хорошо, может быть в методе многократного использования, так что только незначительное повторение).
Что мне было интересно, как вы настраиваете виджет? Вы дублируете форму с новыми виджетами или есть способ изменить это динамически?