2

I have a simple form,

class Compose(forms.Form):
    CHOICES = ()    
    recepient = forms.ChoiceField(choices=CHOICES)
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)

Chocies are generated as

def mychoiceview(request):
        subscribed_lists, other_lists = getListOfLists(request.user.email)
        for lst in subscribed_lists:
            # list name and list address
            CHOICES = CHOICES + ((lst[1],lst[0]),)

        #Bind data to form and render

Basically, the user is subscribed to certain lists (from a superset of lists) and can choose (via dropdown) which list he/she wants to send the message to.

The problem is that I cannot find how to bind the "CHOICES" to the django form.

Some solutions online include using models.. but I don't have a queryset... just a dynamically generated tuple of ids I want the choicefield to render.

Any ideas ?

Thanks !

user1349663
  • 595
  • 1
  • 7
  • 21
  • possible duplicate of [django dynamic form choices](http://stackoverflow.com/search?q=django+dynamic+form+choices) – Hedde van der Heide Jul 20 '13 at 09:57
  • this answer is a close approximate: http://stackoverflow.com/questions/8933723/making-choices-in-forms-dynamic , I've also added a more direct answer. – lsh Aug 02 '13 at 10:39

2 Answers2

1

@nnmware's solution is correct, but a little too complex/confusing. Below is a more succinct version that works just as well:

class DynamicBindingForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(DynamicBindingForm, self).__init__(*args, **kwargs)
        self.fields['recipient'] = forms.ChoiceField(choices=db_lookup_choices())

where db_lookup_choices is a call to some database or other set of dynamic data and returns a list of pairs for choices: [('val', 'Label'),('val2', 'Label2')]

lsh
  • 658
  • 5
  • 12
  • And where you access to "request" in this solution? – nnmware Aug 03 '13 at 15:36
  • you have control of the constructor so just pass it in as a parameter. be sure not to pass it to the parent class though. – lsh Aug 08 '13 at 15:40
  • User ask - how send parameter? In his variant - parameter- request. You answer non-concrete. – nnmware Aug 08 '13 at 21:02
  • `class DynamicBindingForm(forms.Form): def __init__(self, request, *args, **kwargs): super(DynamicBindingForm, self).__init__(*args, **kwargs) self.fields['recipient'] = forms.ChoiceField(choices=get_choices(request))` – lsh Aug 11 '13 at 19:03
  • This only for old generic view(deprecated in future versions). For Class-based view need using get_form_kwargs method. But yes- now it's normal work, but CBV is better. – nnmware Aug 11 '13 at 19:20
  • 1
    You're nit-picking and CBV is not necessarily better so remove your downvote. From the docs: "Class-based views provide an alternative way to implement views as Python objects instead of functions. They do not replace function-based views" – lsh Aug 18 '13 at 19:47
0

If you using Class-based view, then:

in view make mixin for sending request in form

class RequestToFormMixin(object):
    def get_form_kwargs(self):
        kwargs = super(RequestToFormMixin, self).get_form_kwargs()
        kwargs.update({'request': self.request})
        return kwargs

class YouView(RequestToFormMixin, CreateView):
    model = YouModel
    # etc

in form make mixin for receive request from view

class RequestMixinForm(forms.Form):
    def __init__(self, *args, **kwargs):
        request = kwargs.pop('request')
        super(RequestMixinForm, self).__init__(*args, **kwargs)
        self._request = request

class Compose(RequestMixinForm):
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)

    def __init__(self, *args, **kwargs):
        super(Compose, self).__init__(*args, **kwargs)
        subscribed_lists, other_lists = getListOfLists(self._request.user.email)
        for lst in subscribed_lists:
            # list name and list address
            CHOICES = CHOICES + ((lst[1],lst[0]),)    
        self.fields['recipient'] = forms.ChoiceField(choices=CHOICES)
nnmware
  • 930
  • 5
  • 15