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

File newforms-admin-6477-generic-edit-inline.patch, 9.8 KB (added by Honza Král, 17 years ago)

Matching django version 6477

  • django/contrib/admin/options.py

    commit 015c9b884376c82a1b53ccd11728449d1b119d26
    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 bab9580..d650a1e 100644
    a b  
    11from django import oldforms, template
    22from django import newforms as forms
    33from django.newforms.formsets import all_valid
    4 from django.contrib.contenttypes.models import ContentType
    54from django.contrib.admin import widgets
    65from django.contrib.admin.util import get_deleted_objects
    76from django.core.exceptions import ImproperlyConfigured, PermissionDenied
    class ModelAdmin(BaseModelAdmin):  
    451450            return HttpResponseRedirect("../")
    452451
    453452    def render_change_form(self, model, context, add=False, change=False, form_url=''):
     453        from django.contrib.contenttypes.models import ContentType
    454454        opts = model._meta
    455455        app_label = opts.app_label
    456456        ordered_objects = opts.get_ordered_objects()
    class InlineModelAdmin(BaseModelAdmin):  
    721721    template = None
    722722    verbose_name = None
    723723    verbose_name_plural = None
     724    formset = None
    724725
    725726    def __init__(self, parent_model, admin_site):
    726727        self.admin_site = admin_site
    class InlineModelAdmin(BaseModelAdmin):  
    738739            fields = flatten_fieldsets(self.declared_fieldsets)
    739740        else:
    740741            fields = None
    741         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)
     742        return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields,
     743                    formfield_callback=self.formfield_for_dbfield, extra=self.extra, formset=self.formset)
    742744
    743745    def formset_change(self, request, obj):
    744746        """Returns an InlineFormSet class for use in admin change views."""
    class InlineModelAdmin(BaseModelAdmin):  
    746748            fields = flatten_fieldsets(self.declared_fieldsets)
    747749        else:
    748750            fields = None
    749         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)
     751        return forms.inline_formset(self.parent_model, self.model, fk_name=self.fk_name, fields=fields,
     752                    formfield_callback=self.formfield_for_dbfield, extra=self.extra, formset=self.formset)
    750753
    751754    def fieldsets_add(self, request):
    752755        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..bdf9985 100644
    a b class GenericRel(ManyToManyRel):  
    260260        self.multiple = True
    261261        assert not (self.raw_id_admin and self.filter_interface), \
    262262            "Generic relations may not use both raw_id_admin and filter_interface"
     263
     264from django.newforms.models import BaseModelFormSet, formset_for_model, save_instance
     265from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
     266
     267def get_foreign_key(model, ct_field_name, id_field_name):
     268    opts = model._meta
     269    # avoid circular import
     270    from django.db.models import ForeignKey
     271    from django.contrib.contenttypes.models import ContentType
     272    opts = model._meta
     273
     274    # if there is no field called `ct_field_name` let the exception propagate
     275    ct = opts.get_field(ct_field_name)
     276    if not isinstance(ct, ForeignKey) or ct.rel.to != ContentType:
     277        raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % (ct_field_name))
     278
     279    # if there is no field called `id_field_name` let the exception propagate
     280    obj_id = opts.get_field(id_field_name)
     281
     282    return ct, obj_id
     283
     284def inline_formset(model, ct_field_name, id_field_name, fields=None, extra=3, orderable=False, deletable=True, formfield_callback=lambda f: f.formfield(), formset=None):
     285    """
     286    Returns an ``InlineFormset`` for the given kwargs.
     287
     288    You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
     289    to ``parent_model``.
     290    """
     291    ct, obj_id = get_foreign_key(model, ct_field_name, id_field_name)
     292    # let the formset handle object deletion by default
     293    FormSet = formset_for_model(model, formset=formset or GenericInlineFormset, fields=fields,
     294                                formfield_callback=formfield_callback,
     295                                extra=extra, orderable=orderable,
     296                                deletable=deletable)
     297    # HACK: remove the ForeignKey to the parent from every form
     298    # This should be done a line above before we pass 'fields' to formset_for_model
     299    # an 'omit' argument would be very handy here
     300    try:
     301        del FormSet.form_class.base_fields[ct.name]
     302        del FormSet.form_class.base_fields[obj_id.name]
     303    except KeyError:
     304        pass
     305    FormSet.ct = ct
     306    FormSet.obj_id = obj_id
     307    return FormSet
     308
     309class GenericInlineFormset(BaseModelFormSet):
     310    """A formset for child objects related to a parent."""
     311    def __init__(self, instance=None, data=None, files=None):
     312        self.instance = instance
     313        # is there a better way to get the object descriptor?
     314        self.rel_name = self.ct.name + '_' + self.obj_id.name
     315        super(GenericInlineFormset, self).__init__(data, files, instances=self.get_inline_objects(), prefix=self.rel_name)
     316
     317    def get_inline_objects(self):
     318        # This import is done here to avoid circular import importing this module
     319        from django.contrib.contenttypes.models import ContentType
     320        if self.instance is None:
     321            return []
     322        return self.model._default_manager.filter( **{
     323                self.ct.name : ContentType.objects.get_for_model(self.instance),
     324                self.obj_id.name : self.instance._get_pk_val()
     325            })
     326
     327    def save_new(self, form, commit=True):
     328        # This import is done here to avoid circular import importing this module
     329        from django.contrib.contenttypes.models import ContentType
     330        kwargs = {
     331            self.ct.get_attname(): ContentType.objects.get_for_model(self.instance).id,
     332            self.obj_id.get_attname(): self.instance._get_pk_val(),
     333        }
     334        new_obj = self.model(**kwargs)
     335        return save_instance(form, new_obj, commit=commit)
     336
     337class GenericInlineModelAdmin(InlineModelAdmin):
     338    ct_field_name = None
     339    id_field_name = None
     340    def formset_add(self, request):
     341        """Returns an GenericInlineFormSet class for use in admin add views."""
     342        if self.declared_fieldsets:
     343            fields = flatten_fieldsets(self.declared_fieldsets)
     344        else:
     345            fields = None
     346        return inline_formset(self.model,  self.ct_field_name, self.id_field_name, fields=fields,
     347                    formfield_callback=self.formfield_for_dbfield, extra=self.extra, formset=self.formset)
     348
     349    def formset_change(self, request, obj):
     350        """Returns an GenericInlineFormSet class for use in admin change views."""
     351        if self.declared_fieldsets:
     352            fields = flatten_fieldsets(self.declared_fieldsets)
     353        else:
     354            fields = None
     355        return inline_formset(self.model,  self.ct_field_name, self.id_field_name, fields=fields,
     356                    formfield_callback=self.formfield_for_dbfield, extra=self.extra, formset=self.formset)
     357
     358class GenericStackedInline(GenericInlineModelAdmin):
     359    template = 'admin/edit_inline/stacked.html'
     360
     361class GenericTabularInline(GenericInlineModelAdmin):
     362    template = 'admin/edit_inline/tabular.html'
     363
  • django/db/models/query.py

    diff --git a/django/db/models/query.py b/django/db/models/query.py
    index 4d0d295..636ae72 100644
    a b from django.db.models import signals, loading  
    55from django.dispatch import dispatcher
    66from django.utils.datastructures import SortedDict
    77from django.utils.encoding import smart_unicode
    8 from django.contrib.contenttypes import generic
    98import datetime
    109import operator
    1110import re
    def lookup_inner(path, lookup_type, value, opts, table, column):  
    11191118
    11201119def delete_objects(seen_objs):
    11211120    "Iterate through a list of seen classes, and remove any instances that are referred to"
     1121    from django.contrib.contenttypes import generic
    11221122    qn = connection.ops.quote_name
    11231123    ordered_classes = seen_objs.keys()
    11241124    ordered_classes.reverse()
  • django/newforms/models.py

    diff --git a/django/newforms/models.py b/django/newforms/models.py
    index 5fdbc4d..a27a9e8 100644
    a b def get_foreign_key(parent_model, model, fk_name=None):  
    338338            raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))
    339339    return fk
    340340
    341 def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orderable=False, deletable=True, formfield_callback=lambda f: f.formfield()):
     341def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orderable=False, deletable=True, formfield_callback=lambda f: f.formfield(), formset=None):
    342342    """
    343343    Returns an ``InlineFormset`` for the given kwargs.
    344344
    def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orde  
    347347    """
    348348    fk = get_foreign_key(parent_model, model, fk_name=fk_name)
    349349    # let the formset handle object deletion by default
    350     FormSet = formset_for_model(model, formset=InlineFormset, fields=fields,
     350    FormSet = formset_for_model(model, formset=formset or InlineFormset, fields=fields,
    351351                                formfield_callback=formfield_callback,
    352352                                extra=extra, orderable=orderable,
    353353                                deletable=deletable)
Back to Top