Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining two forms in one Django view

Tags:

python

django

I am working on adding more functionality to the polls app that is made in the official Django tutorial. One of the things I am working on is making Polls/Choices creatable by logged in users (instead of in an admin screen, where the tutorial leaves us).

I am looking to create a view where a user can create the a Poll, and then as well include some Choices to associate to the Poll. The Django Admin automagically does it, and I am not sure how to go about writing this out in a view.

To start with, these are my relevant files:

models.py

import datetime

from django.db import models
from django.utils import timezone


class Poll(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __unicode__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

class Choice(models.Model):
    question = models.ForeignKey(Poll)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __unicode__(self):
        return self.choice_text

forms.py

from django import forms
from .models import Poll, Choice
from datetime import datetime

class PollForm(forms.ModelForm):
    question_text = forms.CharField(max_length=200, help_text="Please enter the question.")
    pub_date = forms.DateTimeField(widget=forms.HiddenInput(), initial = datetime.now())

    class Meta:
        model = Poll
        fields = ("__all__")

class ChoiceForm(forms.ModelForm):
    choice_text = forms.CharField(max_length=200, help_text="Please enter choices.")
    votes = forms.IntegerField(widget=forms.HiddenInput(),initial=0)
    exclude = ('poll',)

views.py

def add_poll(request):
    # A HTTP POST?
    if request.method == 'POST':
        form = PollForm(request.POST)

        # Have we been provided with a valid form?
        if form.is_valid():
            # Save the new category to the database.
            form.save(commit=True)

            # Now call the index() view.
            # The user will be shown the homepage.
            return render(request, 'polls/index.html', {})
        else:
            # The supplied form contained errors - just print them to the terminal.
            print form.errors
    else:
        # If the request was not a POST, display the form to enter details.
        form = PollForm()

    # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render(request, 'polls/add_poll.html', {'form': form})

Currently, my view allows me a user to add a poll. I am just not sure how to go about adapting it to pass the entered text as the Poll model's question_text, to the Choice model, and in turn, the ChoiceForm.

like image 564
ploo Avatar asked Jan 20 '15 20:01

ploo


People also ask

How does Django handle multiple forms?

Here we created a viewset, we define two forms to render one is student form and the other is teacher form. We defined the HTML which we have to render. We define what to do when a form is submitted under get_success_url. In form_valid, we save the form data and verify if both the forms are right or not.

What is form Is_valid () in Django?

The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class. It returns True if data is valid and place all data into a cleaned_data attribute.

What is formset in Django?

A formset is a layer of abstraction to work with multiple forms on the same page. It can be best compared to a data grid. Let's say you have the following form: >>> from django import forms >>> class ArticleForm(forms.


1 Answers

Formsets are the way to do it in django.

First add default value for Poll.pub_date field:

class Poll(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published', default=timezone.now)

Then make forms a bit simpler:

class PollForm(forms.ModelForm):
    class Meta:
        model = Poll
        fields = ('question_text', )

class ChoiceForm(forms.ModelForm):
    class Meta:
        model = Choice
        fields = ('choice_text',)

Add formset support to your view:

from django.forms.formsets import formset_factory

def add_poll(request):
    ChoiceFormSet = formset_factory(ChoiceForm, extra=3,
                                    min_num=2, validate_min=True)
    if request.method == 'POST':
        form = PollForm(request.POST)
        formset = ChoiceFormSet(request.POST)
        if all([form.is_valid(), formset.is_valid()]):
            poll = form.save()
            for inline_form in formset:
                if inline_form.cleaned_data:
                    choice = inline_form.save(commit=False)
                    choice.question = poll
                    choice.save()
            return render(request, 'polls/index.html', {})
    else:
        form = PollForm()
        formset = ChoiceFormSet()

    return render(request, 'polls/add_poll.html', {'form': form,
                                                   'formset': formset})

And finally your template:

<form method="post">

    {% csrf_token %}

    <table>
        {{ form }}
        {{ formset }}
    </table>

    <button>Add</button>

</form>
like image 104
catavaran Avatar answered Oct 22 '22 04:10

catavaran