Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Inline Model Formset12:18 with Kenneth Love
Something we've actually used before, but in Admin, is inlines. Inlines let us create and edit multiple *related* model instances at once.
Like I've been saying, inline formsets, and formsets in general, aren't necessary something you'll be using all the time. They're a great tool to have in your toolset, though, when you do need them.
How about some docs?
FormWizard (we didn't use this, but I mentioned it so thought you might want to see. It's a way to link several forms together in a row.)
In Django Basics, we made an inline in the admin
to make it a little easier to create steps in our courses.
We can do something very similar with our own forms and model forms.
I'll admit formsets and
inline formsets aren't something I've used very often in my own career.
You may very well have the same experience, but
they're a great thing to know about just in case you do need them.
And so, with that, let's jump into workspaces.
Another way of doing formsets, and it's a way that we've done in the admin,
is actually using what's called an inline formset.
So I'm gonna scroll up here in the docs.
And right over here on the side, it says inline formsets.
Now inline formsets are different from regular formsets
because inline form sets appear in the model form for another model.
It's kinda like working in admin when we had the inlines for
working with our courses so that we could add steps to the courses.
This is the same idea, but it's for whatever model or form that you want.
So, let's see about how to.add those.
I'm gonna do this a little bit backwards, maybe?
And I'm actually gonna do it over here in question_form.
I'm gonna start on the template first.
So you remember in answer_form,
we just printed out formset, like that.
So we can totally do that with the model formsets, but
they don't always look that great that way.
So I don't want to do it that way, [LAUGH] I want to do it in a nicer way.
So what I'm gonna do, is right here, after this form.as_p,
this is where I am gonna add in the extra bits.
So first we need to add in formset.managment_form,
and this is a special set of fields that control how many items represented,
how many forms there are, stuff like that.
So, this is an important form for controlling whether or
not your formset is valid.
And then, we're gonna do a bunch of HTML, but
we're gonna add in our forms individually, sort of.
So, role is grid, class is stack and
hover, style="width: 100%".
Cool no problem there.
And we're gonna say order, and then I'm actually gonna copy this row.
So this one's gonna be Text.
And we're gonna take off all of that stuff.
And this one is going to be Correct.
And this one is going to be Delete,
because we're gonna bring in the ability to delete answers as well.
All right, so thenand
we need to add in class="order".
This is for a video or so from now.
We're gonna add in the ability to reorder these using drag and drop, but
let's not worry that for just yet.
So for form in formset, cuz formset is a set of forms.
endfor, all right.
So, then we do a
And we give this a class of answer-form.
And if form.instance.pk.
And we'll say item.
Again this is for our plug in that we're gonna use in a little bit.
Actually I need an else in there, else new.
All right, cool.
And then we need a
And we're gonna say form.id, cuz we want the id to hang around.
And then form.order and that's gonna print
out the HTML field for the order field on the form.
And then form.text.
And then here we're gonna print out form.correct.
And then if we have an instance, we want to offer
them the ability to delete that instance.
and then this field is all caps, which is a little bit strange.
All right and if, oh no, we need an else.
But there's nothing in that one.
And then we close our tr and we close our endfor.
And we close our tbody and our table, okay.
So that's cool, that's all of our HTML work.
And of course I'm gonna have all this in a download for you.
It's a decent amount of work there, isn't it?
All right, so now, let's go over here to forms.py.
So we already have this AnswerFormSet.
We're gonna add a new one that is our AnswerInlineFormSet.
So, AnswerInlineFormSet is forms.inlineformset_factory.
And then we specify the model that the inline is going to appear in.
That's the one that we're saving with.
And then models.answer is the model that we're going to be editing in our form.
And I don't want any extra for right now.
And the fields.
It's weird that we have to specify fields.
But we still have to specify fields, even though we could
just specify them in a form or something.
And then we can tell it the FormSet that we want to use,
which is the AnswerFormSet, and that just handles some of these little tidbits.
That's not required.
And min_num=1, we have to have at least 1.
And then I think we're good for right now.
And then we need to close our FormSet factory.
Let's do an extra 2 for right now.
All right, so that's got our form, all that kinda stuff, so
now let's handle our formset in a view.
The two views that we're gonna need to edit are the edit_question and
So in create_question, right here if we do this form = form_class(),
let's add in answer_forms = forms.AnswerInlineFormSet.
And since we're creating a question, this question has no answers.
So our queryset is going to be models.Answers.objects.none().
And that just says, hey give me a blank queryset, which is fine.
So, let's look down here.
So inside of our POST we get our form class.
We also need to get our answer_forms again.
So answer_forms is gonna be forms.InlineFormSet,
and I realize I forgot the word Answer on there.
And our request.POST goes into that.
And our queryset is, once again,
models.Answer.objects.none() because we don't have any.
So if the form.is.valid and
if the answer_forms are valid, then we wanna do this.
We wanna create the question.
We wanna actually create and save that question.
Then we wanna do answers = answer_forms.save,
and again, commit = False.
This should look very familiar to you.
And then for answer in answers, answer.question = question, answer.save().
Cool, so nothing too special there.
All right, let's go ahead and do the edit one as well.
And then we will finish this up.
Oh, we do need to do 'formset' : answer_forms.
We gotta send that out to the template.
Okay now we need to edit our edit_question view.
And this actually ends up being pretty similar to our create_question view.
So down here where we do the form_class,
we need to add in the answer_forms = forms.AnswerInlineFormSet.
And our queryset here is form.instance.answer_set.all().
And in here we do the same idea.
You know what,
let's just copy and paste.
The one thing different here is we wanna pass in request.POST.
And I have to spell request correctly.
All right, so if the form is valid and
answer_forms is valid, then we wanna do form.save.
And we could actually just do answer_forms.save().
But since we might have new answer_forms,
new answers being filled out,
we need to do our old friend here of,
answers = answer_forms.save(commit=False) for answer in answers.
answer.question = question answer.save().
And that just makes sure that they all have that same thing.
And we need to send back our formset for answer_forms.
And I think we're good.
Let's give it a try.
So let's go to Edit our question.
Here's our question form.
And then here's our inline formset.
All right let's add a new one here.
And let's just say ASCII.
And hit Save.
Let's make sure that it updates correctly.
Okay so that says ASCII.
Okay now let's add a new one.
Let's add Emoji only.
Wow, some days I cannot type.
And now let's hit Save.
And now we've got that one in there as well.
So cool, we have inline formsets and that means we can go back
to our question_form.html and we can take off this answers thing.
Because we don't need that anymore,
no more button down here that says Answers, cuz we don't need to go there.
We can get rid of that view and that template and all of that.
Again, this isn't something I've done very often in my own Django career.
Another area that isn't super common is Django's form wizard.
I'll link to that in the teacher's notes if you want to check it out.
Neither of these things, formsets or form wizards, are everyday needs with Django.
But they're really handy when the need arises.
You need to sign up for Treehouse in order to download course files.Sign up