[Answered ]-Django Model Form: show query form and handle post request for OneToMany fields

1👍

To create forms for models which have a OneToMany relation I would recommend you to use Django’s inline formsets: https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#inline-formsets

It’s a really simple and elegant way to create forms for related models.

To parse the choices, the user entered you could just override the clean method of your form. In this the user content is usually checked and prepared for storing it to the database. https://docs.djangoproject.com/en/1.8/ref/forms/validation/#form-field-default-cleaning

So cleaning could look like this:

class QuestionForm(ModelForm):
    ...
    def clean(self):
        cleaned_data = super(QuestionForm, self).clean()
        if cleaned_data['choice_name'].startswith('Something'):
            raise forms.ValidationError(
                "Choice names cannot start with 'Something'!"
            )

1👍

You models seems to be correct, in order to be able to add mutiple choices in your template you need a formset. In addition you can put a formset and a form inside the same html form in a template and have them be validated individually. Each one only cares about the POST data relevant to them. Something like:

template.html

<form method="post" action="">
    {% csrf_token %}
    {{ choices_formset.management_form }} <!-- used by django to manage formsets -->
    {{ question_form.as_p }}
    {% for form in choices_formset %}
        {{ form.as_p }}
    {% endfor %}
  <button type='submit'>Submit</button>
</form>

views.py

from django.db import IntegrityError, transaction
from django.shortcuts import redirect
from django.forms.formsets import formset_factory
from django.core.urlresolvers import reverse

def new_question(request):
    ChoicesFormset = formset_factory(ChoicesForm)
    if request.method == 'POST':
        question_form = QuestionForm(request.POST)
        choices_formset = ChoicesFormset(request.POST)
        if question_form.is_valid():
            question = Question(**question_form.cleaned_data)
            if choices_formset.is_valid():
                question.save()
                new_choice_list = list()
                append_choice = new_choice_list.append
                for form in choices_formset:
                    form.cleaned_data.update({'question': question})
                    append_choice(Choice(**form.cleaned_data))
                try:
                    with transaction.atomic():
                        Choice.objects.bulk_create(new_choice_list)
                except IntegrityError as e:
                    raise IntegrityError
        return redirect(reverse('question-detail-view', kwargs={'id': question.id}))

def question_detail(request, id):
    question_list = Question.objects.get(id=id)
    return render(request, 'question_detail.html', {'question_list': question_list})

urls.py

url(r'^question/$', new_question, name='new-question-view'),
url(r'^question/(?P<id>\d+)/$', question_detail, name='question-detail-view'),

If you want to use rather Ajax submission rather than django form sumbission check this tutoriel.

👤Dhia

Leave a comment