How to approach dynamic multiple select forms

Take a look at this:

choosing

I am trying present users with a list of options on a Page. The options would derive from queryset taken from a model (say, Opts model). The user’s selections would go to another model (say, Choice store). Users should be able to come back to the page and review (update) their choices as per the queryset. The challenge I am having is how to handle the ChoiceField seeing that it is presenting dynamic data. Where do I put it? For static information, the usual place is the model … in this case, the choices are coming from a query on a different model. The choicelist would differ based on established filter, in any case, it is by no means static.

I am firing the page from a View that subclasses FormView. The view pulls the Form which has the ChoiceField but I cant seem to initialize those choices there since it is dynamic. Changing the contents of the form.choices after initialization doesn’t seem to be working. Is that even possible?

class TheForm(forms.Form):
    """Form for tranfering user selection"""

    userselection = forms.MultipleChoiceField(
        choices=[],
    )

I could initialize that by overriding the __init__() class and pass the queryset. That works in one direction and fails in the other. It works when form is on the way to render (at get_form) but fails when returning from POST because then it need to load the form again to fill in POST data.

What is the best way to address this scenario?

Actually it’s quite easy.

The choices attribute can be passed a callable which returns an iterable of 2-tuples.

That actually happens, although it didn’t solve my problem

I was able to get it working with the following modifications:

Form:

class TheForm(forms.Form):
    """Form for tranfering user selection"""

    userselection = forms.MultipleChoiceField(
        choices=[],
    )

    def __init__(self, *args, **kwargs):
        """initialize the form"""

        super().__init__(*args, **kwargs)
        if 'choices' in kwargs['initial']:
            self.fields["taking"].userselection = kwargs['initial']['choices']

View:

class TheView(FormView):
    """Some view for choosing"""

    form_class = TheForm
    template_name = "path/to/the_template.html"

    def get_form(self, form_class=None):
        """Return an instance of the form to be used in this view."""
        
        if form_class is None:
            form_class = self.get_form_class()
            self.initial['choices'] = source.choose()
        return form_class(**self.get_form_kwargs())

I needed to get the choice loaded into the Form Class as early as possible. Since form already expects the initial dict by default. I introduced the choice list there at get_form() function in the view. Then I picked that up during instantiation (i.e.__init__()) in the Form class and fed the list to the relevant field.

I don’t see how you can say that when you show that you still have:

If you replace that definition of choices with a reference to a callable, it will be called whenever the form is constructed or rendered. You don’t need to do this:

1 Like

Aah! I see what you mean now. I will remember that …

There were other considerations. source.choose() is getting a model, and filtering out columns to construct the choice tuple. If there a way to get source.choose() do that with the right pk, and columnsfk for different users without running a separate query, then your answer is the bomb.

There probably is a way of handling that, but it’s hard to tell from the information provided so far. (Also remember that Django caches query results within the context of a view - multiple retrievals of the same data doesn’t necessarily mean that multiple database queries will occur.)

This forum doesn’t seem to provide a means of accepting a solution. I thought this was an instance of Disqus.

There is a way to do it, you can see the list of topics marked as solved.

I have one particular topic that I opened that has this at the bottom:
image

The checkbox on the left would be what I would select to mark it solved. However, I don’t know what condition(s) cause that box is presented.

I don’t see it

Yes, I understand that - I don’t know under what conditions that box appears or doesn’t appear. It appears frequently enough that many people have marked responses as solutions, but I don’t know why it doesn’t show up everywhere.

I have been told that this has now been made generally available. Please check and let me know.

Yesss! I have also applied it. thanks a lot