Django populate a form.ChoiceField field from a queryset and relate the choice back to the model object
Asked Answered
S

2

25

I have a simple form:

class SubmissionQuickReplyForm(forms.Form):
    comment_text = forms.CharField(label='', required=False, widget=forms.Textarea(attrs={'rows':2}))

I want to add a form.ChoiceField to the form, where the options in the ChoiceField is populated from a queryset.

class SubmissionQuickReplyForm(forms.Form):
        comment_text = forms.CharField(label='', required=False, widget=forms.Textarea(attrs={'rows':2}))
        choice = forms.ChoiceField(...)

For example, if I have:

q = MyChoices.Objects.all()

How can I populate the ChoiceField with the contents of q, so that when I am handling the results of the form in my view, I can get the object back out at the end?

    if request.method == "POST":
        form = SubmissionQuickReplyForm(request.POST)
        if form.is_valid():
            ch = get_object_or_404(MyChoices, pk=?)
            # How do I get my object from the choice form field?
Stubbed answered 14/1, 2016 at 4:1 Comment(0)
G
66

You can use ModelChoiceField instead.

choice = forms.ModelChoiceField(queryset=MyChoices.objects.all())

And you can get by simply call cleaned_data like this.

if request.method == "POST":
    form = SubmissionQuickReplyForm(request.POST)
    if form.is_valid():
        ch = form.cleaned_data.get('choice')
Granddaughter answered 14/1, 2016 at 7:29 Comment(1)
should be MyChoices.objects.all() - objects in lowercase :)Hartsfield
H
14

For ChoiceField you can use

choice = forms.ChoiceField(
    choices=[(choice.pk, choice) for choice in MyChoices.objects.all()]
)

to use it in the form init method

class SubmissionQuickReplyForm(forms.Form):
    comment_text = forms.CharField(
        label='', required=False, widget=forms.Textarea(attrs={'rows':2})
    )
    choice = forms.ChoiceField()

    def __init__(self, *args, **kwargs):
         super(SubmissionQuickReplyForm, self).__init__(*args, **kwargs)

         self.fields['choice'].choices = [
             (choice.pk, choice) for choice in MyChoices.objects.all()
         ]
Huesman answered 23/6, 2017 at 11:55 Comment(3)
^ Don't do this -- it will only be evaluated when the module is loaded, meaning the choices will not be updated as the data changes.Meit
ChoiceField dosen't have a queryset , so it is a way to populate a choiceField @AdamBardHuesman
@DimitrisKougioumtzis What he's trying to say is this will be evaluated when Django boots, so the choices will be static until the server reboots. You'd want to do this in the form __init__ instead.Soredium

© 2022 - 2024 — McMap. All rights reserved.