mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
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
This commit is contained in:
parent
a8687b5dc4
commit
7eb538fd46
@ -96,78 +96,55 @@ class BoundField(object):
|
|||||||
attrs = classes and {'class': ' '.join(classes)} or {}
|
attrs = classes and {'class': ' '.join(classes)} or {}
|
||||||
return self.field.label_tag(contents=contents, attrs=attrs)
|
return self.field.label_tag(contents=contents, attrs=attrs)
|
||||||
|
|
||||||
class InlineOptions(object):
|
class BaseModelAdmin(object):
|
||||||
"""
|
"""Functionality common to both ModelAdmin and InlineAdmin."""
|
||||||
Options for inline editing of ``model`` instances.
|
raw_id_fields = ()
|
||||||
|
fields = None
|
||||||
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):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
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
|
|
||||||
|
|
||||||
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 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.opts.verbose_name
|
|
||||||
|
|
||||||
def verbose_name_plural(self):
|
|
||||||
return self.opts.verbose_name_plural
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def fieldsets(self):
|
|
||||||
"""
|
"""
|
||||||
Generator that yields Fieldset objects for use on add and change admin
|
Hook for specifying the form Field instance for a given database Field
|
||||||
form pages.
|
instance.
|
||||||
|
|
||||||
This default implementation looks at self.fields, but subclasses can
|
If kwargs are given, they're passed to the form Field's constructor.
|
||||||
override this implementation and do something special based on the
|
|
||||||
given HttpRequest object.
|
|
||||||
"""
|
"""
|
||||||
if self.opts.fields is None:
|
# For ManyToManyFields with a filter interface, use a special Widget.
|
||||||
default_fields = [f for f in self.base_form.fields]
|
if isinstance(db_field, models.ManyToManyField) and db_field.name in (self.filter_vertical + self.filter_horizontal):
|
||||||
yield Fieldset(fields=default_fields)
|
kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
|
||||||
else:
|
return db_field.formfield(**kwargs)
|
||||||
for name, options in self.opts.fields:
|
|
||||||
yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
|
|
||||||
|
|
||||||
class ModelAdmin(object):
|
# 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)
|
||||||
|
|
||||||
|
class ModelAdmin(BaseModelAdmin):
|
||||||
"Encapsulates all admin options and functionality for a given model."
|
"Encapsulates all admin options and functionality for a given model."
|
||||||
|
|
||||||
list_display = ('__str__',)
|
list_display = ('__str__',)
|
||||||
@ -181,8 +158,6 @@ class ModelAdmin(object):
|
|||||||
save_on_top = False
|
save_on_top = False
|
||||||
ordering = None
|
ordering = None
|
||||||
js = None
|
js = None
|
||||||
fields = None
|
|
||||||
raw_id_fields = ()
|
|
||||||
prepopulated_fields = {}
|
prepopulated_fields = {}
|
||||||
filter_vertical = ()
|
filter_vertical = ()
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
@ -275,49 +250,6 @@ class ModelAdmin(object):
|
|||||||
for fs in self.fieldsets(request):
|
for fs in self.fieldsets(request):
|
||||||
yield fs
|
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):
|
def has_add_permission(self, request):
|
||||||
"Returns True if the given request has permission to add an object."
|
"Returns True if the given request has permission to add an object."
|
||||||
opts = self.opts
|
opts = self.opts
|
||||||
@ -679,6 +611,78 @@ class ModelAdmin(object):
|
|||||||
def get_inline_formsets(self):
|
def get_inline_formsets(self):
|
||||||
inline_formset_classes = []
|
inline_formset_classes = []
|
||||||
for opts in self.inlines:
|
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)
|
inline_formset_classes.append(inline)
|
||||||
return inline_formset_classes
|
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'))
|
||||||
|
@ -111,7 +111,7 @@ class InlineNode(template.Node):
|
|||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
inline = context[self.inline_var]
|
inline = context[self.inline_var]
|
||||||
t = loader.get_template(inline.opts.template)
|
t = loader.get_template(inline.template)
|
||||||
output = t.render(context)
|
output = t.render(context)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user