Ticket #8160: model_formsets.diff
File model_formsets.diff, 6.2 KB (added by , 16 years ago) |
---|
-
django/forms/models.py
220 220 221 221 def modelform_factory(model, form=ModelForm, fields=None, exclude=None, 222 222 formfield_callback=lambda f: f.formfield()): 223 # HACK: we should be able to construct a ModelForm without creating 224 # and passing in a temporary inner class 225 class Meta: 226 pass 227 setattr(Meta, 'model', model) 228 setattr(Meta, 'fields', fields) 229 setattr(Meta, 'exclude', exclude) 223 import types 224 bases = () 225 if hasattr(form, 'Meta'): 226 bases = (form.Meta, ) 227 Meta = types.ClassType('Meta', bases, {}) 228 229 form_model = getattr(Meta, 'model', None) 230 if form_model: 231 if form_model != model: 232 raise Exception('model %s does not match model %s for ModelForm %s' % 233 (model, form_model, form)) 234 else: 235 setattr(Meta, 'model', model) 236 237 if fields: setattr(Meta, 'fields', fields) 238 if exclude: setattr(Meta, 'exclude', exclude) 239 230 240 class_name = model.__name__ + 'Form' 231 241 return ModelFormMetaclass(class_name, (form,), {'Meta': Meta, 232 242 'formfield_callback': formfield_callback}) … … 242 252 243 253 def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, 244 254 queryset=None, **kwargs): 245 self.queryset = queryset 246 defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix} 247 if self.max_num > 0: 248 qs = self.get_queryset()[:self.max_num] 249 else: 250 qs = self.get_queryset() 251 defaults['initial'] = [model_to_dict(obj) for obj in qs] 255 self.queryset = queryset or self.model._default_manager.get_query_set() 256 257 defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix, 'initial': self.queryset} 252 258 defaults.update(kwargs) 253 259 super(BaseModelFormSet, self).__init__(**defaults) 254 260 255 261 def get_queryset(self): 256 if self.queryset is not None: 257 return self.queryset 258 return self.model._default_manager.get_query_set() 262 return self.queryset 259 263 260 264 def save_new(self, form, commit=True): 261 265 """Saves and returns a new model instance for the given form.""" … … 269 273 """Saves model instances for every form, adding and changing instances 270 274 as necessary, and returns the list of instances. 271 275 """ 276 self.changed_objects = [] 277 self.deleted_objects = [] 278 self.new_objects = [] 272 279 if not commit: 273 280 self.saved_forms = [] 274 281 def save_m2m(): 275 282 for form in self.saved_forms: 276 283 form.save_m2m() 277 284 self.save_m2m = save_m2m 278 return self.save_existing_objects(commit) + self.save_new_objects(commit)279 285 280 def save_existing_objects(self, commit=True):281 self.changed_objects = []282 self.deleted_objects = []283 if not self.get_queryset():284 return []285 286 # Put the objects from self.get_queryset into a dict so they are easy to lookup by pk287 existing_objects = {}288 for obj in self.get_queryset():289 existing_objects[obj.pk] = obj290 286 saved_instances = [] 291 for form in self.initial_forms: 292 obj = existing_objects[form.cleaned_data[self.model._meta.pk.attname]] 287 for form in self.forms: 293 288 if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]: 294 self.deleted_objects.append(obj) 295 obj.delete() 296 else: 297 if form.changed_data: 298 self.changed_objects.append((obj, form.changed_data)) 299 saved_instances.append(self.save_existing(form, obj, commit=commit)) 289 if form.instance: 290 self.deleted_objects.append(obj) 291 obj.delete() 292 else: 293 continue 294 elif form.changed_data: 295 if form.instance: 296 self.changed_objects.append((form.instance, form.changed_data)) 297 saved_instances.append(form.save(commit=commit)) 298 else: 299 self.new_objects.append(form.save(commit=commit)) 300 300 if not commit: 301 301 self.saved_forms.append(form) 302 return saved_instances 302 return saved_instances + self.new_objects 303 303 304 def save_new_objects(self, commit=True):305 self.new_objects = []306 for form in self.extra_forms:307 if not form.has_changed():308 continue309 # If someone has marked an add form for deletion, don't save the310 # object.311 if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:312 continue313 self.new_objects.append(self.save_new(form, commit=commit))314 if not commit:315 self.saved_forms.append(form)316 return self.new_objects317 318 304 def add_fields(self, form, index): 319 305 """Add a hidden field for the object's primary key.""" 320 306 if self.model._meta.has_auto_field: … … 322 308 form.fields[self._pk_field_name] = IntegerField(required=False, widget=HiddenInput) 323 309 super(BaseModelFormSet, self).add_fields(form, index) 324 310 311 def _construct_form(self, i, **kwargs): 312 defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)} 313 if self.data or self.files: 314 defaults['data'] = self.data 315 defaults['files'] = self.files 316 # Allow extra forms to be empty. 317 if i >= self._initial_form_count: 318 defaults['empty_permitted'] = True 319 else: 320 defaults['instance'] = self.queryset[i] 321 322 defaults.update(kwargs) 323 form = self.form(**defaults) 324 self.add_fields(form, i) 325 return form 326 327 325 328 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(), 326 329 formset=BaseModelFormSet, 327 330 extra=1, can_delete=False, can_order=False,