Django

Code

Ticket #4667: newforms-admin-5519-generic-edit-inline.patch

File newforms-admin-5519-generic-edit-inline.patch, 7.8 kB (added by Honza Král <Honza.Kral@gmail.com>, 1 year ago)

rough version of the patch

  • django/contrib/admin/options.py

    old new  
    611612    def get_inline_formsets(self): 
    612613        inline_formset_classes = [] 
    613614        for opts in self.inlines: 
    614             inline = inline_formset(self.model, opts.model, formfield_callback=opts.formfield_for_dbfield, fields=opts.fields, extra=opts.extra) 
     615            inline = inline_formset( 
     616                        self.model, 
     617                        opts.model, 
     618                        formfield_callback=opts.formfield_for_dbfield, 
     619                        fields=opts.fields, 
     620                        extra=opts.extra, 
     621                        fk_name=opts.name, 
     622                        formset=opts.formset 
     623                    ) 
    615624            inline_formset_classes.append(inline) 
    616625        return inline_formset_classes 
    617626 
  • django/contrib/contenttypes/generic.py

    old new  
    258258        self.multiple = True 
    259259        assert not (self.raw_id_admin and self.filter_interface), \ 
    260260            "Generic relations may not use both raw_id_admin and filter_interface" 
     261 
     262from django.newforms.models import InlineFormset, save_instance 
     263class GenericInlineFormset(InlineFormset): 
     264 
     265    @classmethod 
     266    def add_fk( cls, parent_model, model, fk_name ): 
     267        assert ':' in fk_name, "Supply valid content_type:object_id as fk_name." 
     268 
     269        opts = model._meta 
     270        ct_field_name, id_field_name = fk_name.split( ':' ) 
     271        ct = opts.get_field( ct_field_name ) 
     272        obj_id = opts.get_field( id_field_name ) 
     273        # HACK: remove the ForeignKey to the parent from every form 
     274        # This should be done a line above before we pass 'fields' to formset_for_model 
     275        # an 'omit' argument would be very handy here 
     276        try: 
     277            del cls.form_class.base_fields[ct.name] 
     278            del cls.form_class.base_fields[obj_id.name] 
     279        except KeyError: 
     280            pass 
     281 
     282        cls.parent_model = parent_model 
     283        cls.model = model 
     284        cls.ct_field_name = ct_field_name 
     285        cls.id_field_name = id_field_name 
     286        cls.ct = ct 
     287        cls.obj_id = obj_id 
     288 
     289    def get_inline_objects( self ): 
     290        # This import is done here to avoid circular import importing this module 
     291        from django.contrib.contenttypes.models import ContentType 
     292        if self.instance is None: 
     293            return [] 
     294        return self.model._default_manager.filter( **{  
     295                self.ct_field_name : ContentType.objects.get_for_model( self.instance ), 
     296                self.id_field_name : self.instance._get_pk_val()  
     297            }) 
     298 
     299    def save_new(self, form, commit=True): 
     300        # This import is done here to avoid circular import importing this module 
     301        from django.contrib.contenttypes.models import ContentType 
     302        kwargs = { 
     303            self.ct.get_attname(): ContentType.objects.get_for_model( self.instance ).id, 
     304            self.obj_id.get_attname(): self.instance._get_pk_val(), 
     305        } 
     306        new_obj = self.model(**kwargs) 
     307        return save_instance(form, new_obj, commit=commit) 
     308 
  • django/newforms/models.py

    old new  
    282282        from django.db.models.fields.related import RelatedObject 
    283283        self.instance = instance 
    284284        # is there a better way to get the object descriptor? 
    285         self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name() 
    286         super(InlineFormset, self).__init__(data, instances=self.get_inline_objects(), prefix=self.rel_name) 
     285        #self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name() 
     286        super(InlineFormset, self).__init__(data, instances=self.get_inline_objects(), prefix='aaaa' ) #prefix=self.rel_name) 
    287287 
     288    @classmethod 
     289    def add_fk( cls, parent_model, model, fk_name ): 
     290        opts = model._meta 
     291        # figure out what the ForeignKey from model to parent_model is 
     292        if fk_name is None: 
     293            fks_to_parent = [f for f in opts.fields if isinstance(f, ForeignKey) and f.rel.to == parent_model] 
     294            if len(fks_to_parent) == 1: 
     295                fk = fks_to_parent[0] 
     296            elif len(fks_to_parent) == 0: 
     297                raise Exception("%s has no ForeignKey to %s" % (model, parent_model)) 
     298            else: 
     299                raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model)) 
     300        else: 
     301            fk = opts.get_field( fk_name ) 
     302        # HACK: remove the ForeignKey to the parent from every form 
     303        # This should be done a line above before we pass 'fields' to formset_for_model 
     304        # an 'omit' argument would be very handy here 
     305        try: 
     306            del FormSet.form_class.base_fields[fk.name] 
     307        except KeyError: 
     308            pass 
     309 
     310        cls.parent_model = parent_model 
     311        cls.fk_name = fk.name 
     312        cls.fk = fk 
     313 
    288314    def get_inline_objects(self): 
    289315        if self.instance is None: 
    290316            return [] 
     
    295321        new_obj = self.model(**kwargs) 
    296322        return save_instance(form, new_obj, commit=commit) 
    297323 
    298 def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, formfield_callback=lambda f: f.formfield()): 
     324def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, formfield_callback=lambda f: f.formfield(), formset=None): 
    299325    """ 
    300326    Returns an ``InlineFormset`` for the given kwargs. 
    301327     
     
    303329    to ``parent_model``. 
    304330    """ 
    305331    from django.db.models import ForeignKey 
    306     opts = model._meta 
    307     # figure out what the ForeignKey from model to parent_model is 
    308     if fk_name is None: 
    309         fks_to_parent = [f for f in opts.fields if isinstance(f, ForeignKey) and f.rel.to == parent_model] 
    310         if len(fks_to_parent) == 1: 
    311             fk = fks_to_parent[0] 
    312         elif len(fks_to_parent) == 0: 
    313             raise Exception("%s has no ForeignKey to %s" % (model, parent_model)) 
    314         else: 
    315             raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model)) 
    316332    # let the formset handle object deletion by default 
    317     FormSet = formset_for_model(model, formset=InlineFormset, fields=fields, formfield_callback=formfield_callback, extra=extra, deletable=True) 
    318     # HACK: remove the ForeignKey to the parent from every form 
    319     # This should be done a line above before we pass 'fields' to formset_for_model 
    320     # an 'omit' argument would be very handy here 
    321     try: 
    322         del FormSet.form_class.base_fields[fk.name] 
    323     except KeyError: 
    324         pass 
    325     FormSet.parent_model = parent_model 
    326     FormSet.fk_name = fk.name 
    327     FormSet.fk = fk 
     333    FormSet = formset_for_model(model, formset=formset or InlineFormset, fields=fields, formfield_callback=formfield_callback, extra=extra, deletable=True) 
     334    FormSet.add_fk( parent_model, model, fk_name) 
    328335    return FormSet