Tay Ray Chuan home archive

copying fields from model forms in django

Thu, 8 Jul 2010 22:37:08 +0800 | Filed under django admin, django

Recently, I found myself trying to create a model form with fields spanning multiple models. I knew I could just re-define the fields manually, but that makes for poor maintainability (read: too lazy to type).

After some digging in ModelFormMetaclass and modelform_factory(), here's what I came up with:

from django import forms
from django.forms.models import modelform_factory

import models

# the usual deal
ChildForm = modelform_factory(models.Child)


# written in full in anticipation of custom validation, etc.
class ParentForm(forms.ModelForm):
    class Meta:
        model = models.Parent


# does the real magic
def copy_form_fields(src_class, dest_class):
    for name, field in src_class.base_fields.iteritems():
        dest_class.base_fields[name] = field
    return dest_class
    
# alternatively, one could have overriden the meta class.
copy_form_fields(ChildForm, ParentForm)

If you're using these model forms with the admin, as most are apt to, don't forget to decorate the get_form method - it calls modelform_factory() to re-generate the form, so your custom, non-model fields won't get picked up.

from django.contrib import admin
    
class ParentAdmin(admin.ModelAdmin):
    form = ParentForm

    def get_form(self, *args, **kwargs):
        form_class = super(ParentAdmin, self).get_form(*args, **kwargs)
        return copy_form_fields(ChildForm, form_class)
blog comments powered by Disqus