1
  • I have a policy_category model with 16 categories.
  • I have a Response model to record survey answers. The model includes a field to record the respondent's 1-5 rating for each of the policy categories. (policy_1_rank..policy_16_rank, etc.)

I can't figure out how to display the CHOICES I created for each field:

Form Template

 <div><b>How important are each of the following issues or policy areas to you, when you're selecting a candidate for president?</b></div>
<div><br></div>
<ul><div>{{ policy_category.object(pk=1) }}</div></ul>
# show POLICY_1_CHOICES below:
<div>{{ form.policy_1_rank }}</div>

<div><br></div>
<ul><div>{{ policy_category.object(pk=2) }}</div></ul>
# show POLICY_2_CHOICES below:
<div>{{ form.policy_2_rank }}</div>
...

Responses Model:

# Temp Survey Response
class Temporaryresponse(models.Model):
    # Healthcare
    POLICY_1_CHOICES = [
    (1, '1: Extremely supportive of a healthcare system with ONLY private insurance'),
    (2, '2: Somewhat supportive of a healthcare system with ONLY private insurance'),
    (3, '3: Somewhat supportive of a healthcare system with BOTH private insurance and a public insurance option'),
    (4, '4: Extremely supportive of a healthcare system with BOTH private insurance and a public insurance option'),
    (5, '5: Somewhat supportive of a healthcare system with ONLY public insurance (commonly referred to as "universal healthcare")'),
    (6, '6: Extremely supportive of a healthcare system with ONLY public insurance (commonly referred to as "universal healthcare")'),
]
...
# Healthcare
    policy_1_rank = models.IntegerField(blank=True, default=0, choices=POLICY_1_CHOICES)

Forms.py

class NextresponseForm(ModelForm):
    policy_1_rank = forms.IntegerField()
    policy_2_rank = forms.IntegerField()
...

class Meta:
        model = Temporaryresponse
        fields = ['policy_1_rank', 'policy_2_rank',...]

EDIT: Maybe the answer below isn't working because there is a problem with my view. I'm trying to navigate from a first form page "tr.html", save the data, and send the pk of the response to "nr.html" for a second part of the survey. This is working. But is my view of "nr.html" incorrect?

views.py

# Create temporary response view - this saves and goes to nr perfectly. pk produced from saving the response shows in nr link in web browser (myapp/nr/pk# shows here perfectly.)
def tr(request):
    if request.method == "POST":
        form = TemporaryresponseForm(request.POST)
        if form.is_valid():
            tempresponse = form.save()
            tempresponse.save()
            return redirect('nr', pk=tempresponse.pk)
    else:
        form = TemporaryresponseForm()
    return render(request, 'politicalexperimentpollapp/tr.html', {'form': form})


def nr(request, pk):
    tempresponse = get_object_or_404(Temporaryresponse, pk=pk)
    instance = Temporaryresponse.objects.get(pk=pk)
    if request.method == "POST":
        form = NextresponseForm(request.POST, instance=instance)
        if form.is_valid():
            nextresponse = form.save()
            nextresponse.save()
            return redirect('fr', pk=nextresponse.pk)
    else:
        form = NextresponseForm(instance=instance)
    return render(request, 'politicalexperimentpollapp/nr.html', {'tempresponse': tempresponse}, {'form': form})
jm2288
  • 53
  • 8

1 Answers1

0

You can override your form's fields in __init__ to include a forms.ChoiceField:

class NextresponseForm(ModelForm):  
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['policy_1_rank'] = forms.ChoiceField(
            choices=self._meta.model.POLICY_1_CHOICES)

    class Meta:
            model = Temporaryresponse
            fields = ['policy_1_rank', 'policy_2_rank',...]

Update

The easiest way to render a form object in django is to pass it as context in your view:

def some_view(request):
    form = NextresponseForm(request.POST or None)
    context = {'form':form}
    return render(request, 'some_template.html', context)

Then you can access the form by calling form.as_ul in your template:

<ul>
{{ form.as_ul }}
</ul>

Update 2

The last line in your views is incorrect:

return render(request, 'politicalexperimentpollapp/nr.html', {'tempresponse': tempresponse}, {'form': form})

Instead this should be:

return render(request, 'politicalexperimentpollapp/nr.html', {'tempresponse': tempresponse, 'form': form})

context is a dictionary. If you need to pass multiple items to your template, you need to include multiple keys in your context dictionary, not multiple arguments.

Lastly, I'd recommend always initializing forms with request.POST or None, to avoid invalidating your form:

    form = TemporaryresponseForm(request.POST or None)

This a textbook answer to a commonly asked question "Why is form.is_valid() always invalid?".

Lord Elrond
  • 13,430
  • 7
  • 40
  • 80
  • Thanks for your help. When I do this I get this error: 'NextresponseForm' object has no attribute 'model'. – jm2288 Oct 16 '19 at 17:03
  • @jm2288 Sorry, you tried the version before I updated. You can't access `self.model`, so you'll have to use the model directly, or use `self._meta.model`. – Lord Elrond Oct 16 '19 at 17:04
  • Thanks, these two ways don't display any choices in the form. Should I change how I reference it in the html? Right now I'm using
    {{ form.policy_1_rank }}
    – jm2288 Oct 16 '19 at 17:18
  • @jm2288 I added an update to explain the preferred way to render a form. Also **note** that I removed `widget` from `self.fields['policy_1_rank']` (see my update), because `ChoiceField` is a form field object, and not a widget. – Lord Elrond Oct 16 '19 at 17:30
  • Thanks. Since it still isn't working I'm thinking maybe the issue is actually my views.py. I edited my question above. Thank you so much for all of your help. – jm2288 Oct 16 '19 at 17:46
  • Thank you so much. This worked. The only other problem I had above is displaying policy_area(pk=1) in my form html. Would you happen to know how to do this? – jm2288 Oct 16 '19 at 18:10
  • @jm2288 I'm not sure what that is, also it seems a bit out of scope for this question. If you need more help, you should ask a new question and I can assist you further. Thanks – Lord Elrond Oct 16 '19 at 18:13
  • Thanks so much. I will remove that from the question above and put in a new question. Thanks! – jm2288 Oct 16 '19 at 18:14