[Answered ]-How to add a Django form field dynamically depending on if the previous field was filled?

1๐Ÿ‘

A technique I have used is to have an initially hidden field on the form. When the form otherwise becomes valid, I cause it to become visible, and then send the form around again. In class-based views and outline:

class SomeThingForm( forms.Modelform):
    class Meta:
        model=Thing
        fields = [ ...

    confirm = forms.BooleanField( 
        initial=False, required=False, widget=forms.widgets.HiddenInput,
        label='Confirm your inputs?' )

class SomeView( CreateView): # or UpdateView
    form_class = SomeThingForm
    template_name = 'whatever'

    def form_valid( self, form):

        _warnings = []
        # have a look at cleaned_data
        # generate _warnings (a list of 2-tuples) about things which
        # aren't automatically bad data but merit another look

        if not form.cleaned_data['confirm'] and _warnings:
            form.add_error('confirm', 'Correct possible typos and override if sure')
            for field,error_text in _warnings:
                form.add_error( field, error_text) # 'foo', 'Check me'
                # make the confirm field visible
                form.fields['confirm'].widget = forms.widgets.Select(
                    choices=((0, 'No'), (1, 'Yes')) )
            # treat the form as invalid (which it now is!)
            return self.form_invalid( form)

    # OK it's come back with confirm=True
    form.save()  # save the model
    return redirect( ...)

For this question, I think you would replace confirm with sms_challenge, a Charfield or IntegerField, initially hidden, with a default value that will never be a correct answer. When the rest of the form validates, form_valid() gets invoked, and then the same program flow, except you also emit the SMS to the phone number in cleaned_data.

        _warnings = [] 
        # retrieve sms_challenge that was sent
        if form.cleaned_data['sms_challenge'] != sms_challenge:
            _warnings.append( ['sms_challenge', 'Sorry, that's not right'] )
        if _warnings:
            ...
            form.fields['sms_challenge'].widget = forms.widgets.TextInput
            return self.form_invalid( form)

I think that ought to work.

๐Ÿ‘คnigel222

Leave a comment