~ubuntu-branches/ubuntu/saucy/python-django/saucy-updates

« back to all changes in this revision

Viewing changes to django/forms/formsets.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone, Jakub Wilk, Luke Faraone
  • Date: 2013-05-09 15:10:47 UTC
  • mfrom: (1.1.21) (4.4.27 sid)
  • Revision ID: package-import@ubuntu.com-20130509151047-aqv8d71oj9wvcv8c
Tags: 1.5.1-2
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Luke Faraone ]
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from __future__ import absolute_import
 
1
from __future__ import absolute_import, unicode_literals
2
2
 
3
3
from django.core.exceptions import ValidationError
4
4
from django.forms import Form
5
5
from django.forms.fields import IntegerField, BooleanField
6
6
from django.forms.util import ErrorList
7
7
from django.forms.widgets import Media, HiddenInput
8
 
from django.utils.encoding import StrAndUnicode
 
8
from django.utils.encoding import python_2_unicode_compatible
9
9
from django.utils.safestring import mark_safe
 
10
from django.utils import six
 
11
from django.utils.six.moves import xrange
10
12
from django.utils.translation import ugettext as _
11
13
 
12
14
 
34
36
        self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput)
35
37
        super(ManagementForm, self).__init__(*args, **kwargs)
36
38
 
37
 
class BaseFormSet(StrAndUnicode):
 
39
@python_2_unicode_compatible
 
40
class BaseFormSet(object):
38
41
    """
39
42
    A collection of instances of the same Form class.
40
43
    """
52
55
        # construct the forms in the formset
53
56
        self._construct_forms()
54
57
 
55
 
    def __unicode__(self):
 
58
    def __str__(self):
56
59
        return self.as_table()
57
60
 
58
61
    def __iter__(self):
66
69
    def __len__(self):
67
70
        return len(self.forms)
68
71
 
69
 
    def __nonzero__(self):
 
72
    def __bool__(self):
70
73
        """All formsets have a management form which is not included in the length"""
71
74
        return True
72
75
 
73
 
    def _management_form(self):
 
76
    def __nonzero__(self):      # Python 2 compatibility
 
77
        return type(self).__bool__(self)
 
78
 
 
79
    @property
 
80
    def management_form(self):
74
81
        """Returns the ManagementForm instance for this FormSet."""
75
82
        if self.is_bound:
76
83
            form = ManagementForm(self.data, auto_id=self.auto_id, prefix=self.prefix)
83
90
                MAX_NUM_FORM_COUNT: self.max_num
84
91
            })
85
92
        return form
86
 
    management_form = property(_management_form)
87
93
 
88
94
    def total_form_count(self):
89
95
        """Returns the total number of forms in this FormSet."""
121
127
        """
122
128
        Instantiates and returns the i-th form instance in a formset.
123
129
        """
124
 
        defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)}
 
130
        defaults = {
 
131
            'auto_id': self.auto_id,
 
132
            'prefix': self.add_prefix(i),
 
133
            'error_class': self.error_class,
 
134
            }
125
135
        if self.is_bound:
126
136
            defaults['data'] = self.data
127
137
            defaults['files'] = self.files
138
148
        self.add_fields(form, i)
139
149
        return form
140
150
 
141
 
    def _get_initial_forms(self):
 
151
    @property
 
152
    def initial_forms(self):
142
153
        """Return a list of all the initial forms in this formset."""
143
154
        return self.forms[:self.initial_form_count()]
144
 
    initial_forms = property(_get_initial_forms)
145
155
 
146
 
    def _get_extra_forms(self):
 
156
    @property
 
157
    def extra_forms(self):
147
158
        """Return a list of all the extra forms in this formset."""
148
159
        return self.forms[self.initial_form_count():]
149
 
    extra_forms = property(_get_extra_forms)
150
160
 
151
 
    def _get_empty_form(self, **kwargs):
152
 
        defaults = {
153
 
            'auto_id': self.auto_id,
154
 
            'prefix': self.add_prefix('__prefix__'),
155
 
            'empty_permitted': True,
156
 
        }
157
 
        defaults.update(kwargs)
158
 
        form = self.form(**defaults)
 
161
    @property
 
162
    def empty_form(self):
 
163
        form = self.form(
 
164
            auto_id=self.auto_id,
 
165
            prefix=self.add_prefix('__prefix__'),
 
166
            empty_permitted=True,
 
167
        )
159
168
        self.add_fields(form, None)
160
169
        return form
161
 
    empty_form = property(_get_empty_form)
162
170
 
163
171
    # Maybe this should just go away?
164
 
    def _get_cleaned_data(self):
 
172
    @property
 
173
    def cleaned_data(self):
165
174
        """
166
175
        Returns a list of form.cleaned_data dicts for every form in self.forms.
167
176
        """
168
177
        if not self.is_valid():
169
178
            raise AttributeError("'%s' object has no attribute 'cleaned_data'" % self.__class__.__name__)
170
179
        return [form.cleaned_data for form in self.forms]
171
 
    cleaned_data = property(_get_cleaned_data)
172
180
 
173
 
    def _get_deleted_forms(self):
 
181
    @property
 
182
    def deleted_forms(self):
174
183
        """
175
184
        Returns a list of forms that have been marked for deletion. Raises an
176
185
        AttributeError if deletion is not allowed.
189
198
                if self._should_delete_form(form):
190
199
                    self._deleted_form_indexes.append(i)
191
200
        return [self.forms[i] for i in self._deleted_form_indexes]
192
 
    deleted_forms = property(_get_deleted_forms)
193
201
 
194
 
    def _get_ordered_forms(self):
 
202
    @property
 
203
    def ordered_forms(self):
195
204
        """
196
205
        Returns a list of form in the order specified by the incoming data.
197
206
        Raises an AttributeError if ordering is not allowed.
226
235
        # Return a list of form.cleaned_data dicts in the order specified by
227
236
        # the form data.
228
237
        return [self.forms[i[0]] for i in self._ordering]
229
 
    ordered_forms = property(_get_ordered_forms)
230
238
 
231
239
    @classmethod
232
240
    def get_default_prefix(cls):
242
250
            return self._non_form_errors
243
251
        return self.error_class()
244
252
 
245
 
    def _get_errors(self):
 
253
    @property
 
254
    def errors(self):
246
255
        """
247
256
        Returns a list of form.errors for every form in self.forms.
248
257
        """
249
258
        if self._errors is None:
250
259
            self.full_clean()
251
260
        return self._errors
252
 
    errors = property(_get_errors)
253
261
 
254
262
    def _should_delete_form(self, form):
255
 
        # The way we lookup the value of the deletion field here takes
256
 
        # more code than we'd like, but the form's cleaned_data will
257
 
        # not exist if the form is invalid.
258
 
        field = form.fields[DELETION_FIELD_NAME]
259
 
        raw_value = form._raw_value(DELETION_FIELD_NAME)
260
 
        should_delete = field.clean(raw_value)
261
 
        return should_delete
 
263
        """
 
264
        Returns whether or not the form was marked for deletion.
 
265
        """
 
266
        return form.cleaned_data.get(DELETION_FIELD_NAME, False)
262
267
 
263
268
    def is_valid(self):
264
269
        """
265
 
        Returns True if form.errors is empty for every form in self.forms.
 
270
        Returns True if every form in self.forms is valid.
266
271
        """
267
272
        if not self.is_bound:
268
273
            return False
277
282
                    # This form is going to be deleted so any of its errors
278
283
                    # should not cause the entire formset to be invalid.
279
284
                    continue
280
 
            if bool(self.errors[i]):
281
 
                forms_valid = False
 
285
            forms_valid &= form.is_valid()
282
286
        return forms_valid and not bool(self.non_form_errors())
283
287
 
284
288
    def full_clean(self):
294
298
        # Give self.clean() a chance to do cross-form validation.
295
299
        try:
296
300
            self.clean()
297
 
        except ValidationError, e:
 
301
        except ValidationError as e:
298
302
            self._non_form_errors = self.error_class(e.messages)
299
303
 
300
304
    def clean(self):
317
321
        if self.can_order:
318
322
            # Only pre-fill the ordering field for initial forms.
319
323
            if index is not None and index < self.initial_form_count():
320
 
                form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), initial=index+1, required=False)
 
324
                form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_('Order'), initial=index+1, required=False)
321
325
            else:
322
 
                form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), required=False)
 
326
                form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_('Order'), required=False)
323
327
        if self.can_delete:
324
 
            form.fields[DELETION_FIELD_NAME] = BooleanField(label=_(u'Delete'), required=False)
 
328
            form.fields[DELETION_FIELD_NAME] = BooleanField(label=_('Delete'), required=False)
325
329
 
326
330
    def add_prefix(self, index):
327
331
        return '%s-%s' % (self.prefix, index)
331
335
        Returns True if the formset needs to be multipart, i.e. it
332
336
        has FileInput. Otherwise, False.
333
337
        """
334
 
        return self.forms and self.forms[0].is_multipart()
 
338
        if self.forms:
 
339
            return self.forms[0].is_multipart()
 
340
        else:
 
341
            return self.empty_form.is_multipart()
335
342
 
336
 
    def _get_media(self):
 
343
    @property
 
344
    def media(self):
337
345
        # All the forms on a FormSet are the same, so you only need to
338
346
        # interrogate the first form for media.
339
347
        if self.forms:
340
348
            return self.forms[0].media
341
349
        else:
342
 
            return Media()
343
 
    media = property(_get_media)
 
350
            return self.empty_form.media
344
351
 
345
352
    def as_table(self):
346
353
        "Returns this formset rendered as HTML <tr>s -- excluding the <table></table>."
347
354
        # XXX: there is no semantic division between forms here, there
348
355
        # probably should be. It might make sense to render each form as a
349
356
        # table row with each field as a td.
350
 
        forms = u' '.join([form.as_table() for form in self])
351
 
        return mark_safe(u'\n'.join([unicode(self.management_form), forms]))
 
357
        forms = ' '.join([form.as_table() for form in self])
 
358
        return mark_safe('\n'.join([six.text_type(self.management_form), forms]))
352
359
 
353
360
    def as_p(self):
354
361
        "Returns this formset rendered as HTML <p>s."
355
 
        forms = u' '.join([form.as_p() for form in self])
356
 
        return mark_safe(u'\n'.join([unicode(self.management_form), forms]))
 
362
        forms = ' '.join([form.as_p() for form in self])
 
363
        return mark_safe('\n'.join([six.text_type(self.management_form), forms]))
357
364
 
358
365
    def as_ul(self):
359
366
        "Returns this formset rendered as HTML <li>s."
360
 
        forms = u' '.join([form.as_ul() for form in self])
361
 
        return mark_safe(u'\n'.join([unicode(self.management_form), forms]))
 
367
        forms = ' '.join([form.as_ul() for form in self])
 
368
        return mark_safe('\n'.join([six.text_type(self.management_form), forms]))
362
369
 
363
370
def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
364
371
                    can_delete=False, max_num=None):
371
378
    attrs = {'form': form, 'extra': extra,
372
379
             'can_order': can_order, 'can_delete': can_delete,
373
380
             'max_num': max_num, 'absolute_max': absolute_max}
374
 
    return type(form.__name__ + 'FormSet', (formset,), attrs)
 
381
    return type(form.__name__ + str('FormSet'), (formset,), attrs)
375
382
 
376
383
def all_valid(formsets):
377
384
    """Returns true if every formset in formsets is valid."""