mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
newforms-admin: Refactored edit inline support classes.
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6072 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a3ecc33ed2
commit
d9fb3fed86
@ -118,6 +118,8 @@ class BaseModelAdmin(object):
|
|||||||
fields = None
|
fields = None
|
||||||
filter_vertical = ()
|
filter_vertical = ()
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
|
prepopulated_fields = {}
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
"""
|
"""
|
||||||
Hook for specifying the form Field instance for a given database Field
|
Hook for specifying the form Field instance for a given database Field
|
||||||
@ -161,6 +163,22 @@ class BaseModelAdmin(object):
|
|||||||
# For any other type of field, just call its formfield() method.
|
# For any other type of field, just call its formfield() method.
|
||||||
return db_field.formfield(**kwargs)
|
return db_field.formfield(**kwargs)
|
||||||
|
|
||||||
|
def fieldsets(self, request):
|
||||||
|
"""
|
||||||
|
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.fields is None:
|
||||||
|
default_fields = [f.name for f in self.opts.fields + self.opts.many_to_many if f.editable and not isinstance(f, models.AutoField)]
|
||||||
|
yield Fieldset(fields=default_fields)
|
||||||
|
else:
|
||||||
|
for name, options in self.fields:
|
||||||
|
yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
|
||||||
|
|
||||||
class ModelAdmin(BaseModelAdmin):
|
class ModelAdmin(BaseModelAdmin):
|
||||||
"Encapsulates all admin options and functionality for a given model."
|
"Encapsulates all admin options and functionality for a given model."
|
||||||
__metaclass__ = forms.MediaDefiningClass
|
__metaclass__ = forms.MediaDefiningClass
|
||||||
@ -175,12 +193,16 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
save_as = False
|
save_as = False
|
||||||
save_on_top = False
|
save_on_top = False
|
||||||
ordering = None
|
ordering = None
|
||||||
prepopulated_fields = {}
|
|
||||||
inlines = []
|
inlines = []
|
||||||
|
|
||||||
def __init__(self, model):
|
def __init__(self, model, admin_site):
|
||||||
self.model = model
|
self.model = model
|
||||||
self.opts = model._meta
|
self.opts = model._meta
|
||||||
|
self.admin_site = admin_site
|
||||||
|
self.inline_instances = []
|
||||||
|
for inline_class in self.inlines:
|
||||||
|
inline_instance = inline_class(self.model, self.admin_site)
|
||||||
|
self.inline_instances.append(inline_instance)
|
||||||
|
|
||||||
def __call__(self, request, url):
|
def __call__(self, request, url):
|
||||||
# Check that LogEntry, ContentType and the auth context processor are installed.
|
# Check that LogEntry, ContentType and the auth context processor are installed.
|
||||||
@ -221,22 +243,6 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
|
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
|
||||||
media = property(_media)
|
media = property(_media)
|
||||||
|
|
||||||
def fieldsets(self, request):
|
|
||||||
"""
|
|
||||||
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.fields is None:
|
|
||||||
default_fields = [f.name for f in self.opts.fields + self.opts.many_to_many if f.editable and not isinstance(f, models.AutoField)]
|
|
||||||
yield Fieldset(fields=default_fields)
|
|
||||||
else:
|
|
||||||
for name, options in self.fields:
|
|
||||||
yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
|
|
||||||
|
|
||||||
def fieldsets_add(self, request):
|
def fieldsets_add(self, request):
|
||||||
"Hook for specifying Fieldsets for the add form."
|
"Hook for specifying Fieldsets for the add form."
|
||||||
return list(self.fieldsets(request))
|
return list(self.fieldsets(request))
|
||||||
@ -428,13 +434,19 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
for fs in inline_formsets:
|
for fs in inline_formsets:
|
||||||
media = media + fs.media
|
media = media + fs.media
|
||||||
|
|
||||||
|
inline_admin_formsets = []
|
||||||
|
for inline, formset in zip(self.inline_instances, inline_formsets):
|
||||||
|
fieldsets = list(inline.fieldsets(request))
|
||||||
|
inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
|
||||||
|
inline_admin_formsets.append(inline_admin_formset)
|
||||||
|
|
||||||
c = template.RequestContext(request, {
|
c = template.RequestContext(request, {
|
||||||
'title': _('Add %s') % opts.verbose_name,
|
'title': _('Add %s') % opts.verbose_name,
|
||||||
'adminform': adminForm,
|
'adminform': adminForm,
|
||||||
'is_popup': request.REQUEST.has_key('_popup'),
|
'is_popup': request.REQUEST.has_key('_popup'),
|
||||||
'show_delete': False,
|
'show_delete': False,
|
||||||
'media': media,
|
'media': media,
|
||||||
'bound_inlines': [BoundInline(i, fs) for i, fs in zip(self.inlines, inline_formsets)],
|
'inline_admin_formsets': inline_admin_formsets,
|
||||||
})
|
})
|
||||||
return render_change_form(self, model, model.AddManipulator(), c, add=True)
|
return render_change_form(self, model, model.AddManipulator(), c, add=True)
|
||||||
|
|
||||||
@ -498,6 +510,12 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
for fs in inline_formsets:
|
for fs in inline_formsets:
|
||||||
media = media + fs.media
|
media = media + fs.media
|
||||||
|
|
||||||
|
inline_admin_formsets = []
|
||||||
|
for inline, formset in zip(self.inline_instances, inline_formsets):
|
||||||
|
fieldsets = list(inline.fieldsets(request))
|
||||||
|
inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
|
||||||
|
inline_admin_formsets.append(inline_admin_formset)
|
||||||
|
|
||||||
c = template.RequestContext(request, {
|
c = template.RequestContext(request, {
|
||||||
'title': _('Change %s') % opts.verbose_name,
|
'title': _('Change %s') % opts.verbose_name,
|
||||||
'adminform': adminForm,
|
'adminform': adminForm,
|
||||||
@ -505,7 +523,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
'original': obj,
|
'original': obj,
|
||||||
'is_popup': request.REQUEST.has_key('_popup'),
|
'is_popup': request.REQUEST.has_key('_popup'),
|
||||||
'media': media,
|
'media': media,
|
||||||
'bound_inlines': [BoundInline(i, fs) for i, fs in zip(self.inlines, inline_formsets)],
|
'inline_admin_formsets': inline_admin_formsets,
|
||||||
})
|
})
|
||||||
return render_change_form(self, model, model.ChangeManipulator(object_id), c, change=True)
|
return render_change_form(self, model, model.ChangeManipulator(object_id), c, change=True)
|
||||||
|
|
||||||
@ -609,11 +627,8 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
return render_to_response(template_list, extra_context, context_instance=template.RequestContext(request))
|
return render_to_response(template_list, extra_context, context_instance=template.RequestContext(request))
|
||||||
|
|
||||||
def get_inline_formsets(self):
|
def get_inline_formsets(self):
|
||||||
inline_formset_classes = []
|
for inline in self.inline_instances:
|
||||||
for opts in self.inlines:
|
yield inline.formset_class
|
||||||
inline = forms.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):
|
class InlineModelAdmin(BaseModelAdmin):
|
||||||
"""
|
"""
|
||||||
@ -623,54 +638,20 @@ class InlineModelAdmin(BaseModelAdmin):
|
|||||||
``model`` to its parent. This is required if ``model`` has more than one
|
``model`` to its parent. This is required if ``model`` has more than one
|
||||||
``ForeignKey`` to its parent.
|
``ForeignKey`` to its parent.
|
||||||
"""
|
"""
|
||||||
def __init__(self, model, name=None, extra=3, fields=None, template=None, raw_id_fields=None):
|
model = None
|
||||||
self.model = model
|
fk_name = None
|
||||||
self.opts = model._meta
|
extra = 3
|
||||||
self.name = name
|
template = None
|
||||||
self.extra = extra
|
label = None
|
||||||
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.raw_id_fields = raw_id_fields or ()
|
|
||||||
|
|
||||||
class StackedInline(InlineModelAdmin):
|
def __init__(self, parent_model, admin_site):
|
||||||
default_template = 'admin/edit_inline_stacked.html'
|
self.admin_site = admin_site
|
||||||
|
self.parent_model = parent_model
|
||||||
|
self.opts = self.model._meta
|
||||||
|
# TODO: pass a fields arg into forms.inline_formset if/when we have one
|
||||||
|
self.formset_class = forms.inline_formset(parent_model, self.model, fk_name=self.fk_name, formfield_callback=self.formfield_for_dbfield, extra=self.extra)
|
||||||
|
|
||||||
class TabularInline(InlineModelAdmin):
|
def fieldsets(self, request):
|
||||||
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(self.formset, form, original, self.inline_admin)
|
|
||||||
for form in self.formset.add_forms:
|
|
||||||
yield BoundInlineObject(self.formset, form, None, self.inline_admin)
|
|
||||||
|
|
||||||
def fields(self):
|
|
||||||
return self.formset.form_class.base_fields.values()
|
|
||||||
|
|
||||||
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, formset, form, original, inline_admin):
|
|
||||||
self.formset = formset
|
|
||||||
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
|
Generator that yields Fieldset objects for use on add and change admin
|
||||||
form pages.
|
form pages.
|
||||||
@ -679,20 +660,59 @@ class BoundInlineObject(object):
|
|||||||
override this implementation and do something special based on the
|
override this implementation and do something special based on the
|
||||||
given HttpRequest object.
|
given HttpRequest object.
|
||||||
"""
|
"""
|
||||||
if self.inline_admin.fields is None:
|
if self.fields is None:
|
||||||
default_fields = [f for f in self.base_form.base_fields]
|
yield Fieldset(fields=self.formset_class.form_class.base_fields)
|
||||||
yield Fieldset(fields=default_fields)
|
|
||||||
else:
|
else:
|
||||||
for name, options in self.opts.fields:
|
for name, options in self.fields:
|
||||||
yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
|
yield Fieldset(name, options['fields'], classes=options.get('classes', '').split(' '), description=options.get('description'))
|
||||||
|
|
||||||
|
class StackedInline(InlineModelAdmin):
|
||||||
|
template = 'admin/edit_inline_stacked.html'
|
||||||
|
|
||||||
|
def get_label(self):
|
||||||
|
return self.label or self.model._meta.verbose_name
|
||||||
|
|
||||||
|
class TabularInline(InlineModelAdmin):
|
||||||
|
template = 'admin/edit_inline_tabular.html'
|
||||||
|
|
||||||
|
def get_label(self):
|
||||||
|
return self.label or self.model._meta.verbose_name_plural
|
||||||
|
|
||||||
|
class InlineAdminFormSet(object):
|
||||||
|
"""
|
||||||
|
A wrapper around an inline formset for use in the admin system.
|
||||||
|
"""
|
||||||
|
def __init__(self, inline, formset, fieldsets):
|
||||||
|
self.opts = inline
|
||||||
|
self.formset = formset
|
||||||
|
self.fieldsets = fieldsets
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for form, original in zip(self.formset.change_forms, self.formset.get_inline_objects()):
|
||||||
|
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
|
||||||
|
for form in self.formset.add_forms:
|
||||||
|
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
|
||||||
|
|
||||||
|
def fields(self):
|
||||||
|
# TODO: this needs to respect the field order of self.fieldsets
|
||||||
|
return self.formset.form_class.base_fields.values()
|
||||||
|
|
||||||
|
class InlineAdminForm(AdminForm):
|
||||||
|
"""
|
||||||
|
A wrapper around an inline form for use in the admin system.
|
||||||
|
"""
|
||||||
|
def __init__(self, formset, form, fieldsets, prepopulated_fields, original):
|
||||||
|
self.formset = formset
|
||||||
|
self.original = original
|
||||||
|
super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
|
||||||
|
|
||||||
def pk_field(self):
|
def pk_field(self):
|
||||||
return BoundField(self.base_form, self.formset._pk_field_name, False)
|
return BoundField(self.form, self.formset._pk_field_name, False)
|
||||||
|
|
||||||
def deletion_field(self):
|
def deletion_field(self):
|
||||||
from django.newforms.formsets import DELETION_FIELD_NAME
|
from django.newforms.formsets import DELETION_FIELD_NAME
|
||||||
return BoundField(self.base_form, DELETION_FIELD_NAME, False)
|
return BoundField(self.form, DELETION_FIELD_NAME, False)
|
||||||
|
|
||||||
def ordering_field(self):
|
def ordering_field(self):
|
||||||
from django.newforms.formsets import ORDERING_FIELD_NAME
|
from django.newforms.formsets import ORDERING_FIELD_NAME
|
||||||
return BoundField(self.base_form, ORDERING_FIELD_NAME, False)
|
return BoundField(self.form, ORDERING_FIELD_NAME, False)
|
||||||
|
@ -77,7 +77,7 @@ class AdminSite(object):
|
|||||||
for model in model_or_iterable:
|
for model in model_or_iterable:
|
||||||
if model in self._registry:
|
if model in self._registry:
|
||||||
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
|
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
|
||||||
self._registry[model] = admin_class(model)
|
self._registry[model] = admin_class(model, self)
|
||||||
|
|
||||||
def unregister(self, model_or_iterable):
|
def unregister(self, model_or_iterable):
|
||||||
"""
|
"""
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
{{ bound_inline.formset.management_form }}
|
{{ inline_admin_formset.formset.management_form }}
|
||||||
{% for bound_inline_object in bound_inline %}
|
{% for inline_admin_form in inline_admin_formset %}
|
||||||
<fieldset class="module aligned {{ bfset.fieldset.classes }}">
|
<fieldset class="module aligned {{ bfset.fieldset.classes }}">
|
||||||
<h2>{{ bound_inline.verbose_name|title }} #{{ forloop.counter }}</h2>
|
<h2>{{ inline_admin_formset.opts.get_label|title }} #{{ forloop.counter }}</h2>
|
||||||
{% for bfset in bound_inline_object.form %}
|
{% for bfset in inline_admin_form %}
|
||||||
{% if bfset.fieldset.name %}<h2>{{ bfset.fieldset.name }}</h2>{% endif %}
|
<!-- fieldsets, headers, and descriptions are commented out until we have decent styles for them -->
|
||||||
{% if bfset.fieldset.description %}<div class="description">{{ bfset.fieldset.description }}</div>{% endif %}
|
<!--<fieldset>-->
|
||||||
|
<!--{% if bfset.fieldset.name %}<h2>{{ bfset.fieldset.name }}</h2>{% endif %}-->
|
||||||
|
<!--{% if bfset.fieldset.description %}<div class="description">{{ bfset.fieldset.description }}</div>{% endif %}-->
|
||||||
{% for line in bfset %}
|
{% for line in bfset %}
|
||||||
<div class="form-row{% if line.errors %} errors{% endif %}">
|
<div class="form-row{% if line.errors %} errors{% endif %}">
|
||||||
{{ line.errors }}
|
{{ line.errors }}
|
||||||
@ -18,9 +20,10 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ bound_inline_object.pk_field.field }}
|
<!--</fieldset>-->
|
||||||
{% if bound_inline.formset.deletable %}<div class="form-row">{{ bound_inline_object.deletion_field.field }} {{ bound_inline_object.deletion_field.label_tag }}</div>{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{{ inline_admin_form.pk_field.field }}
|
||||||
|
{% if inline_admin_formset.formset.deletable %}<div class="form-row">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</div>{% endif %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{{ bound_inline.formset.management_form }}
|
{{ inline_admin_formset.formset.management_form }}
|
||||||
<fieldset class="module">
|
<fieldset class="module">
|
||||||
<h2>{{ bound_inline.verbose_name_plural|capfirst|escape }}</h2>
|
<h2>{{ inline_admin_formset.opts.get_label|capfirst|escape }}</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
{% if bound_inline.formset.deletable %}<th>{% trans "Delete" %}?</th>{% endif %}
|
{% if inline_admin_formset.formset.deletable %}<th>{% trans "Delete" %}?</th>{% endif %}
|
||||||
{% for field in bound_inline.fields %}
|
{% for field in inline_admin_formset.fields %}
|
||||||
{% if not field.is_hidden %}
|
{% if not field.is_hidden %}
|
||||||
<th>{{ field.label|capfirst|escape }}</th>
|
<th>{{ field.label|capfirst|escape }}</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr></thead>
|
</tr></thead>
|
||||||
|
|
||||||
{% for bound_inline_object in bound_inline %}
|
{% for inline_admin_form in inline_admin_formset %}
|
||||||
|
|
||||||
<!-- still need optional original object -->
|
<!-- still need optional original object -->
|
||||||
|
|
||||||
{% if bound_inline_object.form.form.errors %}
|
{% if inline_admin_form.form.errors %}
|
||||||
<tr class="errorlist"><td colspan="{{ bound_inline.fields|length }}">
|
<tr class="errorlist"><td colspan="{{ bound_inline.fields|length }}">
|
||||||
{{ bound_inline_object.form.form.errors }}
|
{{ inline_admin_form.form.errors }}
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<tr class="{% cycle row1,row2 %}">
|
<tr class="{% cycle row1,row2 %}">
|
||||||
{{ bound_inline_object.pk_field.field }}
|
{{ inline_admin_form.pk_field.field }}
|
||||||
{% if bound_inline.formset.deletable %}<td>{{ bound_inline_object.deletion_field.field }}</td>{% endif %}
|
{% if inline_admin_formset.formset.deletable %}<td>{{ inline_admin_form.deletion_field.field }}</td>{% endif %}
|
||||||
{% for bfset in bound_inline_object.form %}
|
{% for bfset in inline_admin_form %}
|
||||||
{% for line in bfset %}
|
{% for line in bfset %}
|
||||||
{% for field in line %}
|
{% for field in line %}
|
||||||
<td>{{ field.field }}</td>
|
<td>{{ field.field }}</td>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user