Ticket #4667: 4667-against-7875.patch

File 4667-against-7875.patch, 3.7 KB (added by Honza Král, 16 years ago)
  • django/contrib/contenttypes/generic.py

    commit 1539b7a9ad5f407dee775e764ba4e9702965509d
    Author: Honza Král <Honza.Kral@gmail.com>
    Date:   Mon Jan 28 22:11:44 2008 +0100
    
        Support for edit_inline for generic relations
        
        http://code.djangoproject.com/ticket/4667
    
    diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
    index e91be70..4945b3c 100644
    a b class GenericRel(ManyToManyRel):  
    281281        self.multiple = True
    282282        assert not (self.raw_id_admin and self.filter_interface), \
    283283            "Generic relations may not use both raw_id_admin and filter_interface"
     284
     285from django.newforms.models import BaseModelFormSet, modelformset_factory, save_instance
     286from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
     287
     288class GenericInlineFormset(BaseModelFormSet):
     289    """A formset for child objects related to a parent."""
     290    def __init__(self, instance=None, data=None, files=None):
     291        self.instance = instance
     292        self.rel_name = '-'.join( ( self.model._meta.app_label, self.model._meta.object_name.lower(), self.ct.name,  self.obj_id.name ) )
     293        super(GenericInlineFormset, self).__init__(queryset=self.get_queryset(), data=data, files=files, prefix=self.rel_name)
     294
     295    def get_queryset(self):
     296        # This import is done here to avoid circular import importing this module
     297        from django.contrib.contenttypes.models import ContentType
     298        if self.instance is None:
     299            return []
     300        return self.model._default_manager.filter( **{
     301                self.ct.name : ContentType.objects.get_for_model(self.instance),
     302                self.obj_id.name : self.instance.pk
     303            })
     304
     305    def save_new(self, form, commit=True):
     306        # This import is done here to avoid circular import importing this module
     307        from django.contrib.contenttypes.models import ContentType
     308        kwargs = {
     309            self.ct.get_attname(): ContentType.objects.get_for_model(self.instance).pk,
     310            self.obj_id.get_attname(): self.instance.pk,
     311        }
     312        new_obj = self.model(**kwargs)
     313        return save_instance(form, new_obj, commit=commit)
     314
     315class GenericInlineModelAdmin(InlineModelAdmin):
     316    ct_field_name = None
     317    id_field_name = None
     318    formset = GenericInlineFormset
     319
     320    def get_formset( self, request, obj=None ):
     321        from django.db.models import ForeignKey
     322        from django.contrib.contenttypes.models import ContentType
     323        if self.declared_fieldsets:
     324            fields = flatten_fieldsets(self.declared_fieldsets)
     325        else:
     326            fields = None
     327
     328        opts = self.model._meta
     329        # if there is no field called `ct_field_name` let the exception propagate
     330        ct = opts.get_field(self.ct_field_name)
     331        if not isinstance(ct, ForeignKey) or ct.rel.to != ContentType:
     332            raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % (self.ct_field_name))
     333        obj_id = opts.get_field(self.id_field_name) # let the exception propagate
     334
     335        FormSet = modelformset_factory(self.model, form=self.form,
     336                                        formfield_callback=self.formfield_for_dbfield,
     337                                        formset=self.formset,
     338                                        extra=self.extra, fields=fields, exclude=[ct.name, obj_id.name] )
     339        FormSet.ct = ct
     340        FormSet.obj_id = obj_id
     341        return FormSet
     342
     343class GenericStackedInline(GenericInlineModelAdmin):
     344    template = 'admin/edit_inline/stacked.html'
     345
     346class GenericTabularInline(GenericInlineModelAdmin):
     347    template = 'admin/edit_inline/tabular.html'
     348
Back to Top