Ticket #8160: model_formsets2.diff

File model_formsets2.diff, 7.5 KB (added by justinf, 7 years ago)

new patch that passes all but one test

  • django/forms/models.py

     
    222222
    223223def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
    224224                       formfield_callback=lambda f: f.formfield()):
    225     # HACK: we should be able to construct a ModelForm without creating
    226     # and passing in a temporary inner class
    227     class Meta:
    228         pass
    229     setattr(Meta, 'model', model)
    230     setattr(Meta, 'fields', fields)
    231     setattr(Meta, 'exclude', exclude)
     225    import types
     226    bases = ()
     227    if hasattr(form, 'Meta'):
     228        bases = (form.Meta, )
     229    Meta = types.ClassType('Meta', bases, {})
     230
     231    form_model = getattr(Meta, 'model', None)
     232    if form_model:
     233        if form_model != model:
     234            raise Exception('model %s does not match model %s for ModelForm %s' %
     235                (model, form_model, form))
     236    else:
     237        setattr(Meta, 'model', model)
     238
     239    if fields: setattr(Meta, 'fields', fields)
     240    if exclude: setattr(Meta, 'exclude', exclude)
     241
    232242    class_name = model.__name__ + 'Form'
    233243    return ModelFormMetaclass(class_name, (form,), {'Meta': Meta,
    234244                              'formfield_callback': formfield_callback})
     
    244254
    245255    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
    246256                 queryset=None, **kwargs):
    247         self.queryset = queryset
    248         defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
     257        self._queryset = queryset
    249258        if self.max_num > 0:
    250             qs = self.get_queryset()[:self.max_num]
    251         else:
    252             qs = self.get_queryset()
    253         defaults['initial'] = [model_to_dict(obj) for obj in qs]
     259            self._queryset = self.get_queryset()[:self.max_num]       
     260        defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
     261        defaults['initial'] = [model_to_dict(obj) for obj in self.get_queryset()]
    254262        defaults.update(kwargs)
    255263        super(BaseModelFormSet, self).__init__(**defaults)
    256264
    257265    def get_queryset(self):
    258         if self.queryset is not None:
    259             return self.queryset
    260         return self.model._default_manager.get_query_set()
     266        if not self._queryset:
     267            self._queryset = self.model._default_manager.get_query_set()
     268        return self._queryset
    261269
    262     def save_new(self, form, commit=True):
    263         """Saves and returns a new model instance for the given form."""
    264         return save_instance(form, self.model(), commit=commit)
    265 
    266     def save_existing(self, form, instance, commit=True):
    267         """Saves and returns an existing model instance for the given form."""
    268         return save_instance(form, instance, commit=commit)
    269 
    270270    def save(self, commit=True):
    271271        """Saves model instances for every form, adding and changing instances
    272272        as necessary, and returns the list of instances.
    273273        """
     274        self.changed_objects = []
     275        self.deleted_objects = []
     276        self.new_objects = []
     277        saved_instances = []
     278
    274279        if not commit:
    275280            self.saved_forms = []
    276281            def save_m2m():
    277282                for form in self.saved_forms:
    278283                    form.save_m2m()
    279284            self.save_m2m = save_m2m
    280         return self.save_existing_objects(commit) + self.save_new_objects(commit)
    281285
    282     def save_existing_objects(self, commit=True):
    283         self.changed_objects = []
    284         self.deleted_objects = []
    285         if not self.get_queryset():
    286             return []
    287 
    288         # Put the objects from self.get_queryset into a dict so they are easy to lookup by pk
    289         existing_objects = {}
    290         for obj in self.get_queryset():
    291             existing_objects[obj.pk] = obj
    292         saved_instances = []
    293         for form in self.initial_forms:
    294             obj = existing_objects[form.cleaned_data[self.model._meta.pk.attname]]
    295             if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
    296                 self.deleted_objects.append(obj)
    297                 obj.delete()
    298             else:
    299                 if form.changed_data:
    300                     self.changed_objects.append((obj, form.changed_data))
    301                     saved_instances.append(self.save_existing(form, obj, commit=commit))
    302                     if not commit:
    303                         self.saved_forms.append(form)
    304         return saved_instances
    305 
    306     def save_new_objects(self, commit=True):
    307         self.new_objects = []
    308         for form in self.extra_forms:
     286        for form in self.forms:
    309287            if not form.has_changed():
    310288                continue
    311             # If someone has marked an add form for deletion, don't save the
    312             # object.
    313289            if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
    314                 continue
    315             self.new_objects.append(self.save_new(form, commit=commit))
    316             if not commit:
    317                 self.saved_forms.append(form)
    318         return self.new_objects
     290                if form.instance and form.instance.pk:
     291                    self.deleted_objects.append(form.instance)
     292                    form.instance.delete()
     293            else:
     294                if form.instance.pk:
     295                    self.changed_objects.append((form.instance, form.changed_data))
     296                    saved_instances.append(form.save(commit=commit))
     297                else:
     298                    self.new_objects.append(form.save(commit=commit))
     299                if not commit:
     300                    self.saved_forms.append(form)
     301        return saved_instances + self.new_objects
    319302
    320303    def add_fields(self, form, index):
    321304        """Add a hidden field for the object's primary key."""
     
    324307            form.fields[self._pk_field_name] = IntegerField(required=False, widget=HiddenInput)
    325308        super(BaseModelFormSet, self).add_fields(form, index)
    326309
     310    def _construct_form(self, i, **kwargs):
     311        defaults = {}
     312        if i < self._initial_form_count:
     313            defaults['instance'] = self.get_queryset()[i]
     314        defaults.update(kwargs)
     315        return super(BaseModelFormSet, self)._construct_form(i, **defaults)
     316
     317
    327318def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
    328319                         formset=BaseModelFormSet,
    329320                         extra=1, can_delete=False, can_order=False,
     
    358349            self._initial_form_count = 0
    359350        super(BaseInlineFormSet, self)._construct_forms()
    360351
     352    def _construct_form(self, i, **kwargs):
     353        defaults = {}
     354        if i >= self._initial_form_count and self.instance:
     355            defaults['instance'] = self.model(**{self.fk.get_attname(): self.instance.pk})
     356        defaults.update(kwargs)
     357        return super(BaseInlineFormSet, self)._construct_form(i, **defaults)
     358
    361359    def get_queryset(self):
    362360        """
    363361        Returns this FormSet's queryset, but restricted to children of
    364362        self.instance
    365363        """
    366         kwargs = {self.fk.name: self.instance}
    367         return self.model._default_manager.filter(**kwargs)
     364        if not self._queryset:
     365            kwargs = {self.fk.name: self.instance}
     366            self._queryset = self.model._default_manager.filter(**kwargs)
     367        return self._queryset
    368368
    369     def save_new(self, form, commit=True):
    370         kwargs = {self.fk.get_attname(): self.instance.pk}
    371         new_obj = self.model(**kwargs)
    372         return save_instance(form, new_obj, commit=commit)
    373369
    374370def _get_foreign_key(parent_model, model, fk_name=None):
    375371    """
Back to Top