Django

Code

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

File 4667-generic-edit-inline.patch, 3.6 kB (added by paltman, 2 months ago)

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

  • django/contrib/admin/options.py

    old new  
    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'