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:
parent
ee7a5cdd7d
commit
62aafd8e30
|
@ -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())
|
|
@ -4,7 +4,8 @@ from django.forms.models import modelform_factory, inlineformset_factory
|
||||||
from django.forms.models import BaseInlineFormSet
|
from django.forms.models import BaseInlineFormSet
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.admin import widgets
|
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.core.exceptions import PermissionDenied
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
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):
|
class IncorrectLookupParameters(Exception):
|
||||||
pass
|
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):
|
class BaseModelAdmin(object):
|
||||||
"""Functionality common to both ModelAdmin and InlineAdmin."""
|
"""Functionality common to both ModelAdmin and InlineAdmin."""
|
||||||
raw_id_fields = ()
|
raw_id_fields = ()
|
||||||
|
@ -587,13 +500,13 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
formset = FormSet(instance=self.model())
|
formset = FormSet(instance=self.model())
|
||||||
formsets.append(formset)
|
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
|
media = self.media + adminForm.media
|
||||||
|
|
||||||
inline_admin_formsets = []
|
inline_admin_formsets = []
|
||||||
for inline, formset in zip(self.inline_instances, formsets):
|
for inline, formset in zip(self.inline_instances, formsets):
|
||||||
fieldsets = list(inline.get_fieldsets(request))
|
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)
|
inline_admin_formsets.append(inline_admin_formset)
|
||||||
media = media + inline_admin_formset.media
|
media = media + inline_admin_formset.media
|
||||||
|
|
||||||
|
@ -604,7 +517,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
'show_delete': False,
|
'show_delete': False,
|
||||||
'media': mark_safe(media),
|
'media': mark_safe(media),
|
||||||
'inline_admin_formsets': inline_admin_formsets,
|
'inline_admin_formsets': inline_admin_formsets,
|
||||||
'errors': AdminErrorList(form, formsets),
|
'errors': helpers.AdminErrorList(form, formsets),
|
||||||
'root_path': self.admin_site.root_path,
|
'root_path': self.admin_site.root_path,
|
||||||
}
|
}
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
|
@ -664,13 +577,13 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
formset = FormSet(instance=obj)
|
formset = FormSet(instance=obj)
|
||||||
formsets.append(formset)
|
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
|
media = self.media + adminForm.media
|
||||||
|
|
||||||
inline_admin_formsets = []
|
inline_admin_formsets = []
|
||||||
for inline, formset in zip(self.inline_instances, formsets):
|
for inline, formset in zip(self.inline_instances, formsets):
|
||||||
fieldsets = list(inline.get_fieldsets(request, obj))
|
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)
|
inline_admin_formsets.append(inline_admin_formset)
|
||||||
media = media + inline_admin_formset.media
|
media = media + inline_admin_formset.media
|
||||||
|
|
||||||
|
@ -682,7 +595,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
'is_popup': request.REQUEST.has_key('_popup'),
|
'is_popup': request.REQUEST.has_key('_popup'),
|
||||||
'media': mark_safe(media),
|
'media': mark_safe(media),
|
||||||
'inline_admin_formsets': inline_admin_formsets,
|
'inline_admin_formsets': inline_admin_formsets,
|
||||||
'errors': AdminErrorList(form, formsets),
|
'errors': helpers.AdminErrorList(form, formsets),
|
||||||
'root_path': self.admin_site.root_path,
|
'root_path': self.admin_site.root_path,
|
||||||
}
|
}
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
|
@ -868,62 +781,3 @@ class StackedInline(InlineModelAdmin):
|
||||||
|
|
||||||
class TabularInline(InlineModelAdmin):
|
class TabularInline(InlineModelAdmin):
|
||||||
template = 'admin/edit_inline/tabular.html'
|
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())
|
|
||||||
|
|
|
@ -43,6 +43,18 @@ def unquote(s):
|
||||||
myappend('_' + item)
|
myappend('_' + item)
|
||||||
return "".join(res)
|
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):
|
def _nest_help(obj, depth, val):
|
||||||
current = obj
|
current = obj
|
||||||
for i in range(depth):
|
for i in range(depth):
|
||||||
|
|
Loading…
Reference in New Issue