Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Django Forms Inlines and Media Inline Model Formset

Django InlineFormset with GCBV (Generic Class Based Views)

I want to add the Inline Model Formset to a GCBV, CreateView.

In the video is done with FBV, and the Class Based View is not available.

I tried to overwrite the get and post functions but it is rendering only the main form, can you provide me with a snippet, guide how to do this ?

5 Answers

Lars Wettmann
Lars Wettmann
15,376 Points

BTW, check out this StackOverview post http://stackoverflow.com/questions/4497684/django-class-based-views-with-inline-model-form-or-formset and take a look at the comments to the answer. That helped me a lot. Also, the free videos on CBV on this page were super helpful as they explain very compact how these CBVs are build up: https://godjango.com/category/class-based-views/

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

This isn't an easy thing to do, sadly. You'll likely want to look at overriding get_form.

Lars Wettmann
Lars Wettmann
15,376 Points

It would be great to have some hints to the whole forms course with class based views. I watched class based views first and then forms. I try to rewrite the whole forms-course in CBV and it cost me days to figure some stuff out cause I cannot seem to find easily understandable documentation on it - and treehouse doesn't provide hints, unfortunately. That would be great though if you could give some hints in the teacher's notes.

I think you are a great teacher, Kenneth - thanks for the good courses.

Lars Wettmann
Lars Wettmann
15,376 Points

I just finished to rewrite the QuizCreateView with inline formsets. And this is how I did it. It should help you, Ciprian Bortos

class QuestionCreateView(LoginRequiredMixin, CreateView):
    question_type       =   ""
    template_name       =   "courses/question_form.html"
    #pk_url_kwarg       =   "quiz_pk"
    #context_object_name =  "quiz"

    def dispatch(self, request, *args, **kwargs):
        self.question_type =    kwargs.get('question_type')
        # call the view
        return super().dispatch(request, *args, **kwargs)

    def get_form(self, form_class=None):
        if self.question_type == 'tf':
            form_class =    forms.TrueFalseQuestionForm
        else:
            form_class =    forms.MultipleChoiceQuestionForm

        return form_class(**self.get_form_kwargs())

    def get(self, request, *args, **kwargs):
        self.object     =   None
        if self.question_type == 'tf':
            return self.render_to_response(self.get_context_data())
        else:
            answer_forms    =   forms.AnswerInlineFormSet(
                queryset=models.Answer.objects.none()
            )
            return self.render_to_response(self.get_context_data(formset=answer_forms))

    def post(self, request, *args, **kwargs):
        #self.object    =   None
        form            =   self.get_form()
        if self.question_type == 'tf':
            if form.is_valid():
                return self.form_valid(form)
            else:
                return self.form_invalid(form)
        else:
            answer_forms    =   forms.AnswerInlineFormSet(
                request.POST,
                queryset=models.Answer.objects.none()
            )
            if form.is_valid() and answer_forms.is_valid():
                return self.form_valid(form, answer_forms)
            else:
                return self.form_invalid(form, answer_forms)

    def form_valid(self, form, formset=None):
        if self.question_type == 'tf':
            return super().form_valid(form)
        else:
            question            =   form.save(commit=False)
            question.quiz_id    =   self.kwargs['quiz_pk']
            question.save()

            answers             =   formset.save(commit=False)
            for answer in answers:
                answer.question =   question
                answer.save() 
            return super().form_valid(form) #equals to return HttpResponseRedirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        ''' only used for the page title '''
        context             =   super().get_context_data(**kwargs)
        context['quiz']     =   models.Quiz.objects.get(id=self.kwargs['quiz_pk'])
        return context

Perhaps you have any tipps, Kenneth Love ?

Kenneth Love
Kenneth Love
Treehouse Guest Teacher

Hmm, first off, what's up with that equals alignment? No bueno, according to PEP 8.

I'd probably override get_form_class instead of get_form, and pop the kwarg off in there instead of dispatch (try to leave dispatch alone as much as possible.

Other than that, it looks OK. How's testing on it?

Lars Wettmann
Lars Wettmann
15,376 Points

Thanks for getting back Kenneth Love . Highly appreciate it. The equals alignment are my bad habits from PHP programming.. oopsi. I'll check PEP8 and stop with it right away ;)

I made the QuizUpdateView work by now. I'll see if I can refactor both and post here again.

It works fine as far as I can tell from clicking around on the site. Haven't done any tests yet.