app/django/contrib/admin/helpers.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 
       
     2 from django import forms
       
     3 from django.conf import settings
       
     4 from django.utils.html import escape
       
     5 from django.utils.safestring import mark_safe
       
     6 from django.utils.encoding import force_unicode
       
     7 from django.contrib.admin.util import flatten_fieldsets
       
     8 from django.contrib.contenttypes.models import ContentType
       
     9 
       
    10 class AdminForm(object):
       
    11     def __init__(self, form, fieldsets, prepopulated_fields):
       
    12         self.form, self.fieldsets = form, fieldsets
       
    13         self.prepopulated_fields = [{
       
    14             'field': form[field_name],
       
    15             'dependencies': [form[f] for f in dependencies]
       
    16         } for field_name, dependencies in prepopulated_fields.items()]
       
    17 
       
    18     def __iter__(self):
       
    19         for name, options in self.fieldsets:
       
    20             yield Fieldset(self.form, name, **options)
       
    21 
       
    22     def first_field(self):
       
    23         try:
       
    24             fieldset_name, fieldset_options = self.fieldsets[0]
       
    25             field_name = fieldset_options['fields'][0]
       
    26             if not isinstance(field_name, basestring):
       
    27                 field_name = field_name[0]
       
    28             return self.form[field_name]
       
    29         except (KeyError, IndexError):
       
    30             pass
       
    31         try:
       
    32             return iter(self.form).next()
       
    33         except StopIteration:
       
    34             return None
       
    35 
       
    36     def _media(self):
       
    37         media = self.form.media
       
    38         for fs in self:
       
    39             media = media + fs.media
       
    40         return media
       
    41     media = property(_media)
       
    42 
       
    43 class Fieldset(object):
       
    44     def __init__(self, form, name=None, fields=(), classes=(), description=None):
       
    45         self.form = form
       
    46         self.name, self.fields = name, fields
       
    47         self.classes = u' '.join(classes)
       
    48         self.description = description
       
    49 
       
    50     def _media(self):
       
    51         if 'collapse' in self.classes:
       
    52             return forms.Media(js=['%sjs/admin/CollapsedFieldsets.js' % settings.ADMIN_MEDIA_PREFIX])
       
    53         return forms.Media()
       
    54     media = property(_media)
       
    55 
       
    56     def __iter__(self):
       
    57         for field in self.fields:
       
    58             yield Fieldline(self.form, field)
       
    59 
       
    60 class Fieldline(object):
       
    61     def __init__(self, form, field):
       
    62         self.form = form # A django.forms.Form instance
       
    63         if isinstance(field, basestring):
       
    64             self.fields = [field]
       
    65         else:
       
    66             self.fields = field
       
    67 
       
    68     def __iter__(self):
       
    69         for i, field in enumerate(self.fields):
       
    70             yield AdminField(self.form, field, is_first=(i == 0))
       
    71 
       
    72     def errors(self):
       
    73         return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
       
    74 
       
    75 class AdminField(object):
       
    76     def __init__(self, form, field, is_first):
       
    77         self.field = form[field] # A django.forms.BoundField instance
       
    78         self.is_first = is_first # Whether this field is first on the line
       
    79         self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
       
    80 
       
    81     def label_tag(self):
       
    82         classes = []
       
    83         if self.is_checkbox:
       
    84             classes.append(u'vCheckboxLabel')
       
    85             contents = force_unicode(escape(self.field.label))
       
    86         else:
       
    87             contents = force_unicode(escape(self.field.label)) + u':'
       
    88         if self.field.field.required:
       
    89             classes.append(u'required')
       
    90         if not self.is_first:
       
    91             classes.append(u'inline')
       
    92         attrs = classes and {'class': u' '.join(classes)} or {}
       
    93         return self.field.label_tag(contents=contents, attrs=attrs)
       
    94 
       
    95 class InlineAdminFormSet(object):
       
    96     """
       
    97     A wrapper around an inline formset for use in the admin system.
       
    98     """
       
    99     def __init__(self, inline, formset, fieldsets):
       
   100         self.opts = inline
       
   101         self.formset = formset
       
   102         self.fieldsets = fieldsets
       
   103 
       
   104     def __iter__(self):
       
   105         for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
       
   106             yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
       
   107         for form in self.formset.extra_forms:
       
   108             yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
       
   109 
       
   110     def fields(self):
       
   111         for field_name in flatten_fieldsets(self.fieldsets):
       
   112             yield self.formset.form.base_fields[field_name]
       
   113 
       
   114     def _media(self):
       
   115         media = self.opts.media + self.formset.media
       
   116         for fs in self:
       
   117             media = media + fs.media
       
   118         return media
       
   119     media = property(_media)
       
   120 
       
   121 class InlineAdminForm(AdminForm):
       
   122     """
       
   123     A wrapper around an inline form for use in the admin system.
       
   124     """
       
   125     def __init__(self, formset, form, fieldsets, prepopulated_fields, original):
       
   126         self.formset = formset
       
   127         self.original = original
       
   128         if original is not None:
       
   129             self.original.content_type_id = ContentType.objects.get_for_model(original).pk
       
   130         self.show_url = original and hasattr(original, 'get_absolute_url')
       
   131         super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
       
   132 
       
   133     def pk_field(self):
       
   134         return AdminField(self.form, self.formset._pk_field.name, False)
       
   135 
       
   136     def deletion_field(self):
       
   137         from django.forms.formsets import DELETION_FIELD_NAME
       
   138         return AdminField(self.form, DELETION_FIELD_NAME, False)
       
   139 
       
   140     def ordering_field(self):
       
   141         from django.forms.formsets import ORDERING_FIELD_NAME
       
   142         return AdminField(self.form, ORDERING_FIELD_NAME, False)
       
   143 
       
   144 class AdminErrorList(forms.util.ErrorList):
       
   145     """
       
   146     Stores all errors for the form/formsets in an add/change stage view.
       
   147     """
       
   148     def __init__(self, form, inline_formsets):
       
   149         if form.is_bound:
       
   150             self.extend(form.errors.values())
       
   151             for inline_formset in inline_formsets:
       
   152                 self.extend(inline_formset.non_form_errors())
       
   153                 for errors_in_inline_form in inline_formset.errors:
       
   154                     self.extend(errors_in_inline_form.values())