Skip to content

Commit

Permalink
Moved admin form helpers to their own module to clean-up django/contr…
Browse files Browse the repository at this point in the history
…ib/admin/options.py a little bit.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8433 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
brosner committed Aug 18, 2008
1 parent ee7a5cd commit 62aafd8
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 154 deletions.
141 changes: 141 additions & 0 deletions django/contrib/admin/helpers.py
Original file line number Original file line Diff line number Diff line change
@@ -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())
162 changes: 8 additions & 154 deletions django/contrib/admin/options.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
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
Expand All @@ -26,94 +27,6 @@
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 = ()
Expand Down Expand Up @@ -587,13 +500,13 @@ def add_view(self, request, form_url='', extra_context=None):
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


Expand All @@ -604,7 +517,7 @@ def add_view(self, request, form_url='', extra_context=None):
'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 {})
Expand Down Expand Up @@ -664,13 +577,13 @@ def change_view(self, request, object_id, extra_context=None):
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


Expand All @@ -682,7 +595,7 @@ def change_view(self, request, object_id, extra_context=None):
'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 {})
Expand Down Expand Up @@ -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())
12 changes: 12 additions & 0 deletions django/contrib/admin/util.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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):
Expand Down

0 comments on commit 62aafd8

Please sign in to comment.