Ticket #4667: 4667-generic-edit-inline.patch

File 4667-generic-edit-inline.patch, 3.6 KB (added by paltman, 16 years ago)

Cleaned up previous patch to work with existing code base (r7771).

  • django/contrib/admin/options.py

     
    22from django import newforms as forms
    33from django.newforms.formsets import all_valid
    44from django.newforms.models import modelform_factory, inlineformset_factory
    5 from django.newforms.models import BaseInlineFormset
     5from django.newforms.models import BaseInlineFormset, BaseModelFormSet
     6from django.newforms.models import save_instance, modelformset_factory
    67from django.contrib.contenttypes.models import ContentType
    78from django.contrib.admin import widgets
    89from django.contrib.admin.util import get_deleted_objects
     
    823824    def ordering_field(self):
    824825        from django.newforms.formsets import ORDERING_FIELD_NAME
    825826        return AdminField(self.form, ORDERING_FIELD_NAME, False)
     827
     828
     829class GenericInlineFormset(BaseModelFormSet):
     830    """A formset for child objects related to a parent."""
     831    def __init__(self, data=None, files=None, instance=None, save_as_new=False):
     832        self.save_as_new = save_as_new
     833        self.instance = instance
     834        self.rel_name = '-'.join((self.model._meta.app_label, self.model._meta.object_name.lower(), self.ct.name, self.obj_id.name))
     835        super(GenericInlineFormset, self).__init__(queryset=self.get_queryset(), data=data, files=files, prefix=self.rel_name)
     836 
     837    def get_queryset(self):
     838        if self.instance is None:
     839            return []
     840        return self.model._default_manager.filter( **{
     841                self.ct.name : ContentType.objects.get_for_model(self.instance),
     842                self.obj_id.name : self.instance.pk
     843            })
     844 
     845    def save_new(self, form, commit=True):
     846        kwargs = {
     847            self.ct.get_attname(): ContentType.objects.get_for_model(self.instance).pk,
     848            self.obj_id.get_attname(): self.instance.pk,
     849        }
     850        new_obj = self.model(**kwargs)
     851        return save_instance(form, new_obj, commit=commit)
     852 
     853class GenericInlineModelAdmin(InlineModelAdmin):
     854    ct_field_name = None
     855    id_field_name = None
     856    formset = GenericInlineFormset
     857    can_delete = True
     858    can_order = True
     859
     860    def get_formset( self, request, obj=None ):
     861        if self.declared_fieldsets:
     862            fields = flatten_fieldsets(self.declared_fieldsets)
     863        else:
     864            fields = None
     865 
     866        opts = self.model._meta
     867        ct = opts.get_field(self.ct_field_name)
     868        if not isinstance(ct, models.ForeignKey) or ct.rel.to != ContentType:
     869            raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % (self.ct_field_name))
     870        obj_id = opts.get_field(self.id_field_name) # let the exception propagate
     871 
     872        FormSet = modelformset_factory(self.model,
     873                                        form=self.form,
     874                                        formfield_callback=self.formfield_for_dbfield,
     875                                        formset=self.formset,
     876                                        extra=self.extra,
     877                                        fields=fields,
     878                                        can_delete=self.can_delete,
     879                                        can_order=self.can_order,
     880                                        exclude=[ct.name, obj_id.name] )
     881        FormSet.ct = ct
     882        FormSet.obj_id = obj_id     
     883        return FormSet
     884
     885class GenericStackedInline(GenericInlineModelAdmin):
     886    template = 'admin/edit_inline/stacked.html'
     887 
     888class GenericTabularInline(GenericInlineModelAdmin):
     889    template = 'admin/edit_inline/tabular.html'
Back to Top