summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Kocherhans <joseph@jkocherhans.com>2007-06-20 06:09:33 +0000
committerJoseph Kocherhans <joseph@jkocherhans.com>2007-06-20 06:09:33 +0000
commit7eb538fd46aafca50af9e67b34d89a4ffd668538 (patch)
tree5582fb756fed5440286b7e13076776774e30da90
parenta8687b5dc4c5e462b8740d574a25ab01c283cf4a (diff)
newforms-admin: Extracted a base class for functionality common to both inlines and ModelAdmin.
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@5498 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/admin/options.py224
-rw-r--r--django/contrib/admin/templatetags/admin_modify.py2
2 files changed, 115 insertions, 111 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 4d0c7c8eee..16d0bca59e 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -96,78 +96,55 @@ class BoundField(object):
attrs = classes and {'class': ' '.join(classes)} or {}
return self.field.label_tag(contents=contents, attrs=attrs)
-class InlineOptions(object):
- """
- Options for inline editing of ``model`` instances.
-
- Provide ``name`` to specify the attribute name of the ``ForeignKey`` from
- ``model`` to its parent. This is required if ``model`` has more than one
- ``ForeignKey`` to its parent.
- """
- def __init__(self, model, name=None, extra=3, fields=None, template=None, formfield_callback=lambda f: f.formfield()):
- self.model = model
- self.name = name
- self.extra = extra
- self.fields = fields
- self.template = template or self.default_template
- self.verbose_name = model._meta.verbose_name
- self.verbose_name_plural = model._meta.verbose_name_plural
- self.prepopulated_fields = {}
- self.formfield_callback = formfield_callback
-
-class StackedInline(InlineOptions):
- default_template = 'admin/edit_inline_stacked.html'
-
-class TabularInline(InlineOptions):
- default_template = 'admin/edit_inline_tabular.html'
-
-class BoundInline(object):
- def __init__(self, opts, formset):
- self.opts = opts
- self.formset = formset
+class BaseModelAdmin(object):
+ """Functionality common to both ModelAdmin and InlineAdmin."""
+ raw_id_fields = ()
+ fields = None
- def __iter__(self):
- for form, original in zip(self.formset.change_forms, self.formset.get_inline_objects()):
- yield BoundInlineObject(form, original, self.opts)
- for form in self.formset.add_forms:
- yield BoundInlineObject(form, None, self.opts)
+ def formfield_for_dbfield(self, db_field, **kwargs):
+ """
+ Hook for specifying the form Field instance for a given database Field
+ instance.
- def fields(self):
- # HACK: each form instance has some extra fields. Getting those fields
- # from the form class will take some rearranging. Get them from the
- # first form instance for now.
- return list(self.formset.forms[0])
+ If kwargs are given, they're passed to the form Field's constructor.
+ """
+ # For ManyToManyFields with a filter interface, use a special Widget.
+ if isinstance(db_field, models.ManyToManyField) and db_field.name in (self.filter_vertical + self.filter_horizontal):
+ kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
+ return db_field.formfield(**kwargs)
- def verbose_name(self):
- return self.opts.verbose_name
+ # For DateTimeFields, use a special field and widget.
+ if isinstance(db_field, models.DateTimeField):
+ return forms.SplitDateTimeField(required=not db_field.blank,
+ widget=widgets.AdminSplitDateTime(), label=capfirst(db_field.verbose_name),
+ help_text=db_field.help_text, **kwargs)
- def verbose_name_plural(self):
- return self.opts.verbose_name_plural
+ # For DateFields, add a custom CSS class.
+ if isinstance(db_field, models.DateField):
+ kwargs['widget'] = forms.TextInput(attrs={'class': 'vDateField', 'size': '10'})
+ return db_field.formfield(**kwargs)
-class BoundInlineObject(object):
- def __init__(self, form, original, opts):
- self.opts = opts
- self.base_form = form
- self.form = AdminForm(form, self.fieldsets(), opts.prepopulated_fields)
- self.original = original
+ # For TimeFields, add a custom CSS class.
+ if isinstance(db_field, models.TimeField):
+ kwargs['widget'] = forms.TextInput(attrs={'class': 'vTimeField', 'size': '8'})
+ return db_field.formfield(**kwargs)
- def fieldsets(self):
- """
- Generator that yields Fieldset objects for use on add and change admin
- form pages.
+ # For ForeignKey or ManyToManyFields, use a special widget.
+ if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
+ if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
+ kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
+ return db_field.formfield(**kwargs)
+ else:
+ # Wrap the widget's render() method with a method that adds
+ # extra HTML to the end of the rendered output.
+ formfield = db_field.formfield(**kwargs)
+ formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel)
+ return formfield
- This default implementation looks at self.fields, but subclasses can
- override this implementation and do something special based on the
- given HttpRequest object.
- """
- if self.opts.fields is None:
- default_fields = [f for f in self.base_form.fields]
- yield Fieldset(fields=default_fields)
- else:
- for name, options in self.opts.fields:
- yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
+ # For any other type of field, just call its formfield() method.
+ return db_field.formfield(**kwargs)
-class ModelAdmin(object):
+class ModelAdmin(BaseModelAdmin):
"Encapsulates all admin options and functionality for a given model."
list_display = ('__str__',)
@@ -181,8 +158,6 @@ class ModelAdmin(object):
save_on_top = False
ordering = None
js = None
- fields = None
- raw_id_fields = ()
prepopulated_fields = {}
filter_vertical = ()
filter_horizontal = ()
@@ -275,49 +250,6 @@ class ModelAdmin(object):
for fs in self.fieldsets(request):
yield fs
- def formfield_for_dbfield(self, db_field, **kwargs):
- """
- Hook for specifying the form Field instance for a given database Field
- instance.
-
- If kwargs are given, they're passed to the form Field's constructor.
- """
- # For ManyToManyFields with a filter interface, use a special Widget.
- if isinstance(db_field, models.ManyToManyField) and db_field.name in (self.filter_vertical + self.filter_horizontal):
- kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
- return db_field.formfield(**kwargs)
-
- # For DateTimeFields, use a special field and widget.
- if isinstance(db_field, models.DateTimeField):
- return forms.SplitDateTimeField(required=not db_field.blank,
- widget=widgets.AdminSplitDateTime(), label=capfirst(db_field.verbose_name),
- help_text=db_field.help_text, **kwargs)
-
- # For DateFields, add a custom CSS class.
- if isinstance(db_field, models.DateField):
- kwargs['widget'] = forms.TextInput(attrs={'class': 'vDateField', 'size': '10'})
- return db_field.formfield(**kwargs)
-
- # For TimeFields, add a custom CSS class.
- if isinstance(db_field, models.TimeField):
- kwargs['widget'] = forms.TextInput(attrs={'class': 'vTimeField', 'size': '8'})
- return db_field.formfield(**kwargs)
-
- # For ForeignKey or ManyToManyFields, use a special widget.
- if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
- if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
- kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
- return db_field.formfield(**kwargs)
- else:
- # Wrap the widget's render() method with a method that adds
- # extra HTML to the end of the rendered output.
- formfield = db_field.formfield(**kwargs)
- formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel)
- return formfield
-
- # For any other type of field, just call its formfield() method.
- return db_field.formfield(**kwargs)
-
def has_add_permission(self, request):
"Returns True if the given request has permission to add an object."
opts = self.opts
@@ -679,6 +611,78 @@ class ModelAdmin(object):
def get_inline_formsets(self):
inline_formset_classes = []
for opts in self.inlines:
- inline = inline_formset(self.model, opts.model, formfield_callback=self.formfield_for_dbfield, fields=opts.fields, extra=opts.extra)
+ inline = inline_formset(self.model, opts.model, formfield_callback=opts.formfield_for_dbfield, fields=opts.fields, extra=opts.extra)
inline_formset_classes.append(inline)
return inline_formset_classes
+
+class InlineModelAdmin(BaseModelAdmin):
+ """
+ Options for inline editing of ``model`` instances.
+
+ Provide ``name`` to specify the attribute name of the ``ForeignKey`` from
+ ``model`` to its parent. This is required if ``model`` has more than one
+ ``ForeignKey`` to its parent.
+ """
+ def __init__(self, model, name=None, extra=3, fields=None, template=None):
+ self.model = model
+ self.opts = model._meta
+ self.name = name
+ self.extra = extra
+ self.fields = fields
+ self.template = template or self.default_template
+ self.verbose_name = model._meta.verbose_name
+ self.verbose_name_plural = model._meta.verbose_name_plural
+ self.prepopulated_fields = {}
+
+class StackedInline(InlineModelAdmin):
+ default_template = 'admin/edit_inline_stacked.html'
+
+class TabularInline(InlineModelAdmin):
+ default_template = 'admin/edit_inline_tabular.html'
+
+class BoundInline(object):
+ def __init__(self, inline_admin, formset):
+ self.inline_admin = inline_admin
+ self.formset = formset
+ self.template = inline_admin.template
+
+ def __iter__(self):
+ for form, original in zip(self.formset.change_forms, self.formset.get_inline_objects()):
+ yield BoundInlineObject(form, original, self.inline_admin)
+ for form in self.formset.add_forms:
+ yield BoundInlineObject(form, None, self.inline_admin)
+
+ def fields(self):
+ # HACK: each form instance has some extra fields. Getting those fields
+ # from the form class will take some rearranging. Get them from the
+ # first form instance for now.
+ return list(self.formset.forms[0])
+
+ def verbose_name(self):
+ return self.inline_admin.verbose_name
+
+ def verbose_name_plural(self):
+ return self.inline_admin.verbose_name_plural
+
+class BoundInlineObject(object):
+ def __init__(self, form, original, inline_admin):
+ self.inline_admin = inline_admin
+ self.base_form = form
+ self.form = AdminForm(form, self.fieldsets(), inline_admin.prepopulated_fields)
+ self.original = original
+
+ def fieldsets(self):
+ """
+ Generator that yields Fieldset objects for use on add and change admin
+ form pages.
+
+ This default implementation looks at self.fields, but subclasses can
+ override this implementation and do something special based on the
+ given HttpRequest object.
+ """
+ if self.inline_admin.fields is None:
+ default_fields = [f for f in self.base_form.fields]
+ yield Fieldset(fields=default_fields)
+ else:
+ for name, options in self.opts.fields:
+ yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py
index 1ba5f8f104..663b6bc5d1 100644
--- a/django/contrib/admin/templatetags/admin_modify.py
+++ b/django/contrib/admin/templatetags/admin_modify.py
@@ -111,7 +111,7 @@ class InlineNode(template.Node):
def render(self, context):
inline = context[self.inline_var]
- t = loader.get_template(inline.opts.template)
+ t = loader.get_template(inline.template)
output = t.render(context)
return output