Moved admin form helpers to their own module to clean-up django/contrib/admin/options.py a little bit.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8433 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Brian Rosner 2008-08-18 15:49:58 +00:00
parent ee7a5cdd7d
commit 62aafd8e30
3 changed files with 161 additions and 154 deletions

View File

@ -0,0 +1,141 @@
from django import forms
from django.conf import settings
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
from django.contrib.admin.util import flatten_fieldsets
class AdminForm(object):
def __init__(self, form, fieldsets, prepopulated_fields):
self.form, self.fieldsets = form, fieldsets
self.prepopulated_fields = [{
'field': form[field_name],
'dependencies': [form[f] for f in dependencies]
} for field_name, dependencies in prepopulated_fields.items()]
def __iter__(self):
for name, options in self.fieldsets:
yield Fieldset(self.form, name, **options)
def first_field(self):
for bf in self.form:
return bf
def _media(self):
media = self.form.media
for fs in self:
media = media + fs.media
return media
media = property(_media)
class Fieldset(object):
def __init__(self, form, name=None, fields=(), classes=(), description=None):
self.form = form
self.name, self.fields = name, fields
self.classes = u' '.join(classes)
self.description = description
def _media(self):
if 'collapse' in self.classes:
return forms.Media(js=['%sjs/admin/CollapsedFieldsets.js' % settings.ADMIN_MEDIA_PREFIX])
return forms.Media()
media = property(_media)
def __iter__(self):
for field in self.fields:
yield Fieldline(self.form, field)
class Fieldline(object):
def __init__(self, form, field):
self.form = form # A django.forms.Form instance
if isinstance(field, basestring):
self.fields = [field]
else:
self.fields = field
def __iter__(self):
for i, field in enumerate(self.fields):
yield AdminField(self.form, field, is_first=(i == 0))
def errors(self):
return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
class AdminField(object):
def __init__(self, form, field, is_first):
self.field = form[field] # A django.forms.BoundField instance
self.is_first = is_first # Whether this field is first on the line
self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
def label_tag(self):
classes = []
if self.is_checkbox:
classes.append(u'vCheckboxLabel')
contents = force_unicode(escape(self.field.label))
else:
contents = force_unicode(escape(self.field.label)) + u':'
if self.field.field.required:
classes.append(u'required')
if not self.is_first:
classes.append(u'inline')
attrs = classes and {'class': u' '.join(classes)} or {}
return self.field.label_tag(contents=contents, attrs=attrs)
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.initial_forms, self.formset.get_queryset()):
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
for form in self.formset.extra_forms:
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
def fields(self):
for field_name in flatten_fieldsets(self.fieldsets):
yield self.formset.form.base_fields[field_name]
def _media(self):
media = self.opts.media + self.formset.media
for fs in self:
media = media + fs.media
return media
media = property(_media)
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
self.show_url = original and hasattr(original, 'get_absolute_url')
super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
def pk_field(self):
return AdminField(self.form, self.formset._pk_field_name, False)
def deletion_field(self):
from django.forms.formsets import DELETION_FIELD_NAME
return AdminField(self.form, DELETION_FIELD_NAME, False)
def ordering_field(self):
from django.forms.formsets import ORDERING_FIELD_NAME
return AdminField(self.form, ORDERING_FIELD_NAME, False)
class AdminErrorList(forms.util.ErrorList):
"""
Stores all errors for the form/formsets in an add/change stage view.
"""
def __init__(self, form, inline_formsets):
if form.is_bound:
self.extend(form.errors.values())
for inline_formset in inline_formsets:
self.extend(inline_formset.non_form_errors())
for errors_in_inline_form in inline_formset.errors:
self.extend(errors_in_inline_form.values())

View File

@ -4,7 +4,8 @@ from django.forms.models import modelform_factory, inlineformset_factory
from django.forms.models import BaseInlineFormSet
from django.contrib.contenttypes.models import ContentType
from django.contrib.admin import widgets
from django.contrib.admin.util import quote, unquote, get_deleted_objects
from django.contrib.admin import helpers
from django.contrib.admin.util import quote, unquote, flatten_fieldsets, get_deleted_objects
from django.core.exceptions import PermissionDenied
from django.db import models, transaction
from django.http import Http404, HttpResponse, HttpResponseRedirect
@ -26,94 +27,6 @@ get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
class IncorrectLookupParameters(Exception):
pass
def flatten_fieldsets(fieldsets):
"""Returns a list of field names from an admin fieldsets structure."""
field_names = []
for name, opts in fieldsets:
for field in opts['fields']:
# type checking feels dirty, but it seems like the best way here
if type(field) == tuple:
field_names.extend(field)
else:
field_names.append(field)
return field_names
class AdminForm(object):
def __init__(self, form, fieldsets, prepopulated_fields):
self.form, self.fieldsets = form, fieldsets
self.prepopulated_fields = [{
'field': form[field_name],
'dependencies': [form[f] for f in dependencies]
} for field_name, dependencies in prepopulated_fields.items()]
def __iter__(self):
for name, options in self.fieldsets:
yield Fieldset(self.form, name, **options)
def first_field(self):
for bf in self.form:
return bf
def _media(self):
media = self.form.media
for fs in self:
media = media + fs.media
return media
media = property(_media)
class Fieldset(object):
def __init__(self, form, name=None, fields=(), classes=(), description=None):
self.form = form
self.name, self.fields = name, fields
self.classes = u' '.join(classes)
self.description = description
def _media(self):
from django.conf import settings
if 'collapse' in self.classes:
return forms.Media(js=['%sjs/admin/CollapsedFieldsets.js' % settings.ADMIN_MEDIA_PREFIX])
return forms.Media()
media = property(_media)
def __iter__(self):
for field in self.fields:
yield Fieldline(self.form, field)
class Fieldline(object):
def __init__(self, form, field):
self.form = form # A django.forms.Form instance
if isinstance(field, basestring):
self.fields = [field]
else:
self.fields = field
def __iter__(self):
for i, field in enumerate(self.fields):
yield AdminField(self.form, field, is_first=(i == 0))
def errors(self):
return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
class AdminField(object):
def __init__(self, form, field, is_first):
self.field = form[field] # A django.forms.BoundField instance
self.is_first = is_first # Whether this field is first on the line
self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
def label_tag(self):
classes = []
if self.is_checkbox:
classes.append(u'vCheckboxLabel')
contents = force_unicode(escape(self.field.label))
else:
contents = force_unicode(escape(self.field.label)) + u':'
if self.field.field.required:
classes.append(u'required')
if not self.is_first:
classes.append(u'inline')
attrs = classes and {'class': u' '.join(classes)} or {}
return self.field.label_tag(contents=contents, attrs=attrs)
class BaseModelAdmin(object):
"""Functionality common to both ModelAdmin and InlineAdmin."""
raw_id_fields = ()
@ -587,13 +500,13 @@ class ModelAdmin(BaseModelAdmin):
formset = FormSet(instance=self.model())
formsets.append(formset)
adminForm = AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields)
adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields)
media = self.media + adminForm.media
inline_admin_formsets = []
for inline, formset in zip(self.inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request))
inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets)
inline_admin_formsets.append(inline_admin_formset)
media = media + inline_admin_formset.media
@ -604,7 +517,7 @@ class ModelAdmin(BaseModelAdmin):
'show_delete': False,
'media': mark_safe(media),
'inline_admin_formsets': inline_admin_formsets,
'errors': AdminErrorList(form, formsets),
'errors': helpers.AdminErrorList(form, formsets),
'root_path': self.admin_site.root_path,
}
context.update(extra_context or {})
@ -664,13 +577,13 @@ class ModelAdmin(BaseModelAdmin):
formset = FormSet(instance=obj)
formsets.append(formset)
adminForm = AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
media = self.media + adminForm.media
inline_admin_formsets = []
for inline, formset in zip(self.inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request, obj))
inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets)
inline_admin_formsets.append(inline_admin_formset)
media = media + inline_admin_formset.media
@ -682,7 +595,7 @@ class ModelAdmin(BaseModelAdmin):
'is_popup': request.REQUEST.has_key('_popup'),
'media': mark_safe(media),
'inline_admin_formsets': inline_admin_formsets,
'errors': AdminErrorList(form, formsets),
'errors': helpers.AdminErrorList(form, formsets),
'root_path': self.admin_site.root_path,
}
context.update(extra_context or {})
@ -868,62 +781,3 @@ class StackedInline(InlineModelAdmin):
class TabularInline(InlineModelAdmin):
template = 'admin/edit_inline/tabular.html'
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.initial_forms, self.formset.get_queryset()):
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
for form in self.formset.extra_forms:
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
def fields(self):
for field_name in flatten_fieldsets(self.fieldsets):
yield self.formset.form.base_fields[field_name]
def _media(self):
media = self.opts.media + self.formset.media
for fs in self:
media = media + fs.media
return media
media = property(_media)
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
self.show_url = original and hasattr(original, 'get_absolute_url')
super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
def pk_field(self):
return AdminField(self.form, self.formset._pk_field_name, False)
def deletion_field(self):
from django.forms.formsets import DELETION_FIELD_NAME
return AdminField(self.form, DELETION_FIELD_NAME, False)
def ordering_field(self):
from django.forms.formsets import ORDERING_FIELD_NAME
return AdminField(self.form, ORDERING_FIELD_NAME, False)
class AdminErrorList(forms.util.ErrorList):
"""
Stores all errors for the form/formsets in an add/change stage view.
"""
def __init__(self, form, inline_formsets):
if form.is_bound:
self.extend(form.errors.values())
for inline_formset in inline_formsets:
self.extend(inline_formset.non_form_errors())
for errors_in_inline_form in inline_formset.errors:
self.extend(errors_in_inline_form.values())

View File

@ -43,6 +43,18 @@ def unquote(s):
myappend('_' + item)
return "".join(res)
def flatten_fieldsets(fieldsets):
"""Returns a list of field names from an admin fieldsets structure."""
field_names = []
for name, opts in fieldsets:
for field in opts['fields']:
# type checking feels dirty, but it seems like the best way here
if type(field) == tuple:
field_names.extend(field)
else:
field_names.append(field)
return field_names
def _nest_help(obj, depth, val):
current = obj
for i in range(depth):