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.
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:
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.)
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.