enderv
enderv

Reputation: 203

Django Form setting ChoiceField options as Form is called

I'm trying to integrate with an inventory application and allow users to add parts to inventory through a Django form. I can read from the inventory database but have to write through the API so based on what they enter into the a previous form I want to give them a list of available parts to add.

Here is my form, I set a few choices just as a default:

class PartForm(forms.Form):
    PART_CHOICES = (
    ('BT-J1KND-A', 'BT-J1KND-A'),
    ('BT-J1KND-B', 'BT-J1KND-B'),)
    part = forms.ChoiceField(choices = PART_CHOICES,required = True, label = 'Part to add to Inventory')

And here is where I set the choices

parts_list = part_sql(part)
#build choices
PART_CHOICES= [(p[0],p[0]) for p in parts_list]
form = PartForm()
form.fields['part'].choices = PART_CHOICES

It displays correctly in the template but when I go to hit save and process the form if it is not one of the default choices I put in it says it is not a valid option.

Select a valid choice. BT-J1KND-C is not one of the available choices.

How do I fix this to get it to accept the choices I set as valid options?

Upvotes: 7

Views: 19511

Answers (2)

robjohncox
robjohncox

Reputation: 3665

If you programmatically change one of the fields on a form, I believe you need to call full_clean() on the form afterwards so that the changes get reflected in the form. We do this on an application I work on - here is the code we have modified for your example.

from django.forms import Select

...

field = form.fields['part']
field.choices = PART_CHOICES
field.widget = Select(choices=PART_CHOICES)

form.fields['part'] = field
form.full_clean()

Note that as well as assigning field.choices, we also re-initialize field.widget.

Upvotes: 0

lastmikoi
lastmikoi

Reputation: 343

Once the request gets processed, it seems that your user input goes into an unmodified PartForm, using the hardcoded values.

In order to get the request processed correctly, you need to have a consistent PartForm

You can achieve this smoothly by modifying the field's choices attribute at initialization.

For example:

class ExampleForm(forms.Form):
    CHOICES = (
        ('EXMPL', 'Example'),
    )
    field = forms.ChoiceField(choices=CHOICES, required=True, label='Example')

    def __init__(self, custom_choices=None, *args, **kwargs):
        super(ExampleForm, self).__init__(*args, **kwargs)
        if custom_choices:
            self.fields['field'].choices = custom_choices

And then, just remember to initialize the form correctly, with

form = ExampleForm(my_custom_choices_nested_tuple, ...)

You may also double-check where you're actually processing data (a form = PartForm(request.REQUEST) not mentioned in your copied code, I guess)

Upvotes: 14

Related Questions