Take the 2-minute tour ×

I'm building a support ticket tracking app and have a few models I'd like to create from one page. Tickets belong to a Customer via a ForeignKey. Notes belong to Tickets via a ForeignKey as well. I'd like to have the option of selecting a Customer (that's a whole separate project) OR creating a new Customer, then creating a Ticket and finally creating a Note assigned to the new ticket.

Since I'm fairly new at Django, I tend to work iteratively, trying out new features each time. I've played with ModelForms but I want to hide some of the fields and do some complex validation. It seems like the level of control I'm looking for either requires formsets or doing everything by hand, complete with a tedious, hand-coded template page, which I'm trying to avoid.

Is there some lovely feature I'm missing? does someone have a good reference / example for using formsets? I spent a whole weekend on the API docs for them and I'm still clueless. Is it a design issue if I break down and hand-code everything?

Thanks in advance!

share|improve this question

6 Answers 6

I currently have a workaround functional (it passes my unit tests). It is a good solution to my opinion when you only want to add a limited number of fields from other models.

Am I missing something here ?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile
share|improve this answer

According to Django documentation, inline formsets are for this purpose: "Inline formsets is a small abstraction layer on top of model formsets. These simplify the case of working with related objects via a foreign key".

See https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets

share|improve this answer

I just was in about the same situation a day ago, and here are my 2 cents:

1) I found arguably the shortest and most concise demonstration of multiple model entry in single form here: http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/ .

In a nutshell: Make a form for each model, submit them both to template in a single <form>, using prefix keyarg and have the view handle validation. If there is dependency, just make sure you save the "parent" model before dependant, and use parent's ID for foreign key before commiting save of "child" model. The link has the demo.

2) Maybe formsets can be beaten into doing this, but as far as I delved in, formsets are primarily for entering multiples of the same model, which may be optionally tied to another model/models by foreign keys. However, there seem to be no default option for entering more than one model's data and that's not what formset seems to be meant for.

share|improve this answer

I very recently had the some problem and just figured out how to do this. Assuming you have three classes, Primary, B, C and that B,C have a foreign key to primary

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
                    print "failed"

            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,

This method should allow you to do whatever validation you require, as well as generating all three objects on the same page. I have also used javascript and hidden fields to allow the generation of multiple B,C objects on the same page.

share|improve this answer
In this example, how are you setting the foreign keys for models B and C to point to the Primary model? –  User May 16 '10 at 21:18
I only have two models that I want to show on the same form. But I don't get the exclude = ('primary',) statement. What is primary? If have 2 models CustomerConfig and Contract. Contract has the foreign key to CustomerConfig. Such as customer_config=models.ForeignKey('CustomerPartnerConfiguration') What is 'primary'? –  pitchblack408 Sep 18 at 22:44

This really isn't too hard to implement with ModelForms. So lets say you have Forms A, B, and C. You print out each of the forms and the page and now you need to handle the POST.

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        c.foreignkeytoB = b

Here are the docs for custom validation.

share|improve this answer
hm, I'll have to play with something like this... thanks :D –  neoice Feb 25 '09 at 5:09
btw, I don't think formsets are good solution to the problem you described. I always used them to represent multiple instances of a model. E.g. you have a applicant form and you want 3 references to you make a formset that has 3 instances of the Reference model. –  Jason Christa Feb 25 '09 at 23:58
note that, with the way you do it, the .is_valid() call is not short circuited. If you want to short circuit it, you'll need to delay calling the .is_valid() function until the 'and'. –  Lie Ryan Mar 1 '12 at 5:37

"I want to hide some of the fields and do some complex validation."

I start with the built-in admin interface.

  1. Build the ModelForm to show the desired fields.

  2. Extend the Form with the validation rules within the form. Usually this is a clean method.

    Be sure this part works reasonably well.

Once this is done, you can move away from the built-in admin interface.

Then you can fool around with multiple, partially related forms on a single web page. This is a bunch of template stuff to present all the forms on a single page.

Then you have to write the view function to read and validated the various form things and do the various object saves().

"Is it a design issue if I break down and hand-code everything?" No, it's just a lot of time for not much benefit.

share|improve this answer
I don't know how, therefore don't do it –  orokusaki Sep 23 '11 at 3:54
@orokusaki: What more would you like? That seems to describe a solution. What more should be said? The question is vague, so it's hard to provide actual code. Rather than complain, please provide a suggestion for improvement. What do you suggest? –  S.Lott Sep 23 '11 at 3:57

Your Answer


