Ticket #4667: newforms-admin-6426-generic-edit-inline.patch
File newforms-admin-6426-generic-edit-inline.patch, 9.4 KB (added by , 17 years ago) |
---|
-
django/contrib/admin/options.py
commit 5b9f454eef18f63c85c35e3f2ee903723199b508 Author: Honza Král <Honza.Kral@gmail.com> Date: Tue Oct 2 18:18:24 2007 +0200 Added generic edit inline patch http://code.djangoproject.com/ticket/4667 diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 9018472..ef98bc0 100644
a b class InlineModelAdmin(BaseModelAdmin): 694 694 template = None 695 695 verbose_name = None 696 696 verbose_name_plural = None 697 formset = None 697 698 698 699 def __init__(self, parent_model, admin_site): 699 700 self.admin_site = admin_site … … class InlineModelAdmin(BaseModelAdmin): 711 712 fields = flatten_fieldsets(self.declared_fieldsets) 712 713 else: 713 714 fields = None 714 return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra) 715 return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, 716 formfield_callback=self.formfield_for_dbfield, extra=self.extra, formset=self.formset) 715 717 716 718 def formset_change(self, request, obj): 717 719 """Returns an InlineFormSet class for use in admin change views.""" … … class InlineModelAdmin(BaseModelAdmin): 719 721 fields = flatten_fieldsets(self.declared_fieldsets) 720 722 else: 721 723 fields = None 722 return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra) 724 return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, 725 formfield_callback=self.formfield_for_dbfield, extra=self.extra, formset=self.formset) 723 726 724 727 def fieldsets_add(self, request): 725 728 if self.declared_fieldsets: -
django/contrib/contenttypes/generic.py
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py index b738a26..0612ffc 100644
a b class GenericRel(ManyToManyRel): 260 260 self.multiple = True 261 261 assert not (self.raw_id_admin and self.filter_interface), \ 262 262 "Generic relations may not use both raw_id_admin and filter_interface" 263 264 from django.newforms.models import InlineFormset, save_instance 265 class GenericInlineFormset(InlineFormset): 266 267 @classmethod 268 def add_fk(cls, parent_model, model, fk_name): 269 from django.template.defaultfilters import slugify 270 assert ':' in fk_name, "Supply valid content_type:object_id as fk_name." 271 272 opts = model._meta 273 ct_field_name, id_field_name = fk_name.split(':') 274 ct = opts.get_field( ct_field_name ) 275 obj_id = opts.get_field( id_field_name ) 276 # HACK: remove the ForeignKey to the parent from every form 277 # This should be done a line above before we pass 'fields' to formset_for_model 278 # an 'omit' argument would be very handy here 279 try: 280 del cls.form_class.base_fields[ct.name] 281 del cls.form_class.base_fields[obj_id.name] 282 except KeyError: 283 pass 284 285 cls.parent_model = parent_model 286 cls.model = model 287 cls.ct_field_name = ct_field_name 288 cls.id_field_name = id_field_name 289 cls.ct = ct 290 cls.obj_id = obj_id 291 cls.rel_name = slugify(fk_name) 292 293 def get_inline_objects(self): 294 # This import is done here to avoid circular import importing this module 295 from django.contrib.contenttypes.models import ContentType 296 if self.instance is None: 297 return [] 298 return self.model._default_manager.filter( **{ 299 self.ct_field_name : ContentType.objects.get_for_model(self.instance), 300 self.id_field_name : self.instance._get_pk_val() 301 }) 302 303 def save_new(self, form, commit=True): 304 # This import is done here to avoid circular import importing this module 305 from django.contrib.contenttypes.models import ContentType 306 kwargs = { 307 self.ct.get_attname(): ContentType.objects.get_for_model(self.instance).id, 308 self.obj_id.get_attname(): self.instance._get_pk_val(), 309 } 310 new_obj = self.model(**kwargs) 311 return save_instance(form, new_obj, commit=commit) -
django/newforms/models.py
diff --git a/django/newforms/models.py b/django/newforms/models.py index 5c4dc08..61b8dc7 100644
a b def formset_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formf 295 295 class InlineFormset(BaseModelFormSet): 296 296 """A formset for child objects related to a parent.""" 297 297 def __init__(self, instance=None, data=None, files=None): 298 from django.db.models.fields.related import RelatedObject299 298 self.instance = instance 300 299 # is there a better way to get the object descriptor? 301 self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()302 300 super(InlineFormset, self).__init__(data, files, instances=self.get_inline_objects(), prefix=self.rel_name) 303 301 304 302 def get_inline_objects(self): … … class InlineFormset(BaseModelFormSet): 311 309 new_obj = self.model(**kwargs) 312 310 return save_instance(form, new_obj, commit=commit) 313 311 314 def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orderable=False, deletable=True, formfield_callback=lambda f: f.formfield()): 312 @classmethod 313 def add_fk(cls, parent_model, model, fk_name): 314 from django.db.models import ForeignKey 315 from django.db.models.fields.related import RelatedObject 316 opts = model._meta 317 # figure out what the ForeignKey from model to parent_model is 318 if fk_name is None: 319 fks_to_parent = [f for f in opts.fields if isinstance(f, ForeignKey) and f.rel.to == parent_model] 320 if len(fks_to_parent) == 1: 321 fk = fks_to_parent[0] 322 elif len(fks_to_parent) == 0: 323 raise Exception("%s has no ForeignKey to %s" % (model, parent_model)) 324 else: 325 raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model)) 326 else: 327 fks_to_parent = [f for f in opts.fields if f.name == fk_name] 328 if len(fks_to_parent) == 1: 329 fk = fks_to_parent[0] 330 if not isinstance(fk, ForeignKey) or fk.rel.to != parent_model: 331 raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model)) 332 elif len(fks_to_parent) == 0: 333 raise Exception("%s has no field named '%s'" % (model, fk_name)) 334 # HACK: remove the ForeignKey to the parent from every form 335 # This should be done a line above before we pass 'fields' to formset_for_model 336 # an 'omit' argument would be very handy here 337 try: 338 del cls.form_class.base_fields[fk.name] 339 except KeyError: 340 pass 341 342 cls.parent_model = parent_model 343 cls.fk_name = fk.name 344 cls.rel_name = RelatedObject(fk.rel.to, model, fk).get_accessor_name() 345 cls.fk = fk 346 347 def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orderable=False, 348 deletable=True, formfield_callback=lambda f: f.formfield(), formset=None): 315 349 """ 316 350 Returns an ``InlineFormset`` for the given kwargs. 317 351 318 352 You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey`` 319 353 to ``parent_model``. 320 354 """ 321 from django.db.models import ForeignKey322 opts = model._meta323 # figure out what the ForeignKey from model to parent_model is324 if fk_name is None:325 fks_to_parent = [f for f in opts.fields if isinstance(f, ForeignKey) and f.rel.to == parent_model]326 if len(fks_to_parent) == 1:327 fk = fks_to_parent[0]328 elif len(fks_to_parent) == 0:329 raise Exception("%s has no ForeignKey to %s" % (model, parent_model))330 else:331 raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))332 else:333 fks_to_parent = [f for f in opts.fields if f.name == fk_name]334 if len(fks_to_parent) == 1:335 fk = fks_to_parent[0]336 if not isinstance(fk, ForeignKey) or fk.rel.to != parent_model:337 raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))338 elif len(fks_to_parent) == 0:339 raise Exception("%s has no field named '%s'" % (model, fk_name))340 355 # let the formset handle object deletion by default 341 FormSet = formset_for_model(model, formset= InlineFormset, fields=fields,356 FormSet = formset_for_model(model, formset=formset or InlineFormset, fields=fields, 342 357 formfield_callback=formfield_callback, 343 358 extra=extra, orderable=orderable, 344 359 deletable=deletable) 345 # HACK: remove the ForeignKey to the parent from every form 346 # This should be done a line above before we pass 'fields' to formset_for_model 347 # an 'omit' argument would be very handy here 348 try: 349 del FormSet.form_class.base_fields[fk.name] 350 except KeyError: 351 pass 352 FormSet.parent_model = parent_model 353 FormSet.fk_name = fk.name 354 FormSet.fk = fk 360 FormSet.add_fk(parent_model, model, fk_name) 355 361 return FormSet