Django FormWizard with dynamic forms

I want to implement a simple 2 part of FormWizard. Form 1 will be dynamically generated like this:

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] 

This will dynamically create a form with lists of available options.

My second form, I really don't want input. I just want to display a confirmation screen containing credit card information, apple information and the amount of money (total amount, tax, delivery). When the user clicks OK, I want the purchase of Apple to begin.

I managed to implement the only form method by passing the request.user object to kwargs. However, with the help of FormWizard I can not figure it out.

Am I approaching the problem incorrectly and is FormWizard not the right way? If so, how can the Form __init__ method access the user object from an HTTP request?

+6
django dynamic forms formwizard
source share
5 answers

I don't know if the answer to one question is acceptable for StackOverflow, here is my solution to my own problem.

First, click the FormWizard button.

I have one form. Two types: buy_apples and buy_apples_confirm

The first view only handles GET. It prints an unrelated form with an action to go to the URL of the second view.

In the second view, the POST parameter named "confirm" is checked. If it is absent (as it is not the first time it is loaded), it:

  • Configures the widget on all fields that will be HiddenInput
  • Writes a template that gives an order summary. This template also sets the hidden field called "confirm" to 1 (although this field does not exist on the form)

When the user clicks on the purchase of apples, the form returns and the form buy_apples_confirm is called again. This time there is a POST parameter called "confirm", so we actually process the purchase transaction, and the user receives his apples.

I welcome any criticisms of this method or better ways to handle the situation. I am new to Django and believe that there are many different ways to solve the problem. I want to learn best.

0
source share

I have not used it, but for the situation described it seems that you can try FormPreview instead of the Form Wizard. From the documentation, this seems like what you need.

+4
source share

When I tried to figure out FormWizard, I looked for everything and found answers, such as most of them, that just say they don’t use it. FormPreview will work fine, since the OP is only interested in a single-level form, but the question remains valid in how to use FormWizard.

Despite the fact that this question is so old, I think it is useful to answer here, because this question is asked on so many sites, and I do not see any connecting answer to it, as well as a clear solution in the documents.

I think in terms of the OPs question, overriding process_step is the way to go. The trick is to create a form (or view) inside this method that will receive data from the first form.

I added this form_setup to my form.py as a utility wrapper (thought constructor):

 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 

Then override process_step as follows:

 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]) #(*) ... 

That way, you can dynamically change form_list (*) in the sense that you are changing form_list in an instance of FormWizard, not the form definitions themselves. The wrapper function is important for this function because it returns a function that will instantiate a new Form object, which is then used in FormWizard to call data for the next form and allows you to use the data from the previous one.

Edit: for Erik's comment and clarify the last part.

Also note that process_step will be called in step [0, n] after step n.

+4
source share

Thank you for answering your question. Helped me, but I still have some comments.

FormPreview is not the way to go, because as far as I know, it does not support dynamic forms. It uses a fixed form class to generate from there. But we dynamically generate a function here. Perhaps FormPreview will support this day (or is already doing it, and I don’t know how to do it).

Krys solution is similar to that of FormPreview. There is only a hash left, so the user can change the data in hidden fields or check it again ?. If you check it again, it will not follow DRY because you are duplicating a check (well, maybe in a reusable method, so only a tiny repeat).

What interests me is how do you customize the widget? Are you duplicating a form with new widgets or is there a way to change this dynamically?

0
source share

How to change the call method to take an additional parameter?

something similar to this: http://dw.me/blog/2010/3/18/15/

0
source share

All Articles