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

« back to all changes in this revision

Viewing changes to django/forms/formsets.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2010-05-21 07:52:55 UTC
  • mfrom: (1.3.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20100521075255-ii78v1dyfmyu3uzx
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
from forms import Form
 
2
from django.core.exceptions import ValidationError
2
3
from django.utils.encoding import StrAndUnicode
3
4
from django.utils.safestring import mark_safe
4
5
from django.utils.translation import ugettext as _
5
6
from fields import IntegerField, BooleanField
6
7
from widgets import Media, HiddenInput
7
 
from util import ErrorList, ErrorDict, ValidationError
 
8
from util import ErrorList
8
9
 
9
10
__all__ = ('BaseFormSet', 'all_valid')
10
11
 
11
12
# special field names
12
13
TOTAL_FORM_COUNT = 'TOTAL_FORMS'
13
14
INITIAL_FORM_COUNT = 'INITIAL_FORMS'
 
15
MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS'
14
16
ORDERING_FIELD_NAME = 'ORDER'
15
17
DELETION_FIELD_NAME = 'DELETE'
16
18
 
23
25
    def __init__(self, *args, **kwargs):
24
26
        self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
25
27
        self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
 
28
        self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput)
26
29
        super(ManagementForm, self).__init__(*args, **kwargs)
27
30
 
28
31
class BaseFormSet(StrAndUnicode):
55
58
        else:
56
59
            form = ManagementForm(auto_id=self.auto_id, prefix=self.prefix, initial={
57
60
                TOTAL_FORM_COUNT: self.total_form_count(),
58
 
                INITIAL_FORM_COUNT: self.initial_form_count()
 
61
                INITIAL_FORM_COUNT: self.initial_form_count(),
 
62
                MAX_NUM_FORM_COUNT: self.max_num
59
63
            })
60
64
        return form
61
65
    management_form = property(_management_form)
65
69
        if self.data or self.files:
66
70
            return self.management_form.cleaned_data[TOTAL_FORM_COUNT]
67
71
        else:
68
 
            total_forms = self.initial_form_count() + self.extra
69
 
            if total_forms > self.max_num > 0:
 
72
            initial_forms = self.initial_form_count()
 
73
            total_forms = initial_forms + self.extra
 
74
            # Allow all existing related objects/inlines to be displayed,
 
75
            # but don't allow extra beyond max_num.
 
76
            if initial_forms > self.max_num >= 0:
 
77
                total_forms = initial_forms
 
78
            elif total_forms > self.max_num >= 0:
70
79
                total_forms = self.max_num
71
80
        return total_forms
72
81
 
77
86
        else:
78
87
            # Use the length of the inital data if it's there, 0 otherwise.
79
88
            initial_forms = self.initial and len(self.initial) or 0
80
 
            if initial_forms > self.max_num > 0:
 
89
            if initial_forms > self.max_num >= 0:
81
90
                initial_forms = self.max_num
82
91
        return initial_forms
83
92
 
118
127
        return self.forms[self.initial_form_count():]
119
128
    extra_forms = property(_get_extra_forms)
120
129
 
 
130
    def _get_empty_form(self, **kwargs):
 
131
        defaults = {
 
132
            'auto_id': self.auto_id,
 
133
            'prefix': self.add_prefix('__prefix__'),
 
134
            'empty_permitted': True,
 
135
        }
 
136
        if self.data or self.files:
 
137
            defaults['data'] = self.data
 
138
            defaults['files'] = self.files
 
139
        defaults.update(kwargs)
 
140
        form = self.form(**defaults)
 
141
        self.add_fields(form, None)
 
142
        return form
 
143
    empty_form = property(_get_empty_form)
 
144
 
121
145
    # Maybe this should just go away?
122
146
    def _get_cleaned_data(self):
123
147
        """
144
168
                # if this is an extra form and hasn't changed, don't consider it
145
169
                if i >= self.initial_form_count() and not form.has_changed():
146
170
                    continue
147
 
                if form.cleaned_data[DELETION_FIELD_NAME]:
 
171
                if self._should_delete_form(form):
148
172
                    self._deleted_form_indexes.append(i)
149
173
        return [self.forms[i] for i in self._deleted_form_indexes]
150
174
    deleted_forms = property(_get_deleted_forms)
168
192
                if i >= self.initial_form_count() and not form.has_changed():
169
193
                    continue
170
194
                # don't add data marked for deletion to self.ordered_data
171
 
                if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
 
195
                if self.can_delete and self._should_delete_form(form):
172
196
                    continue
173
197
                self._ordering.append((i, form.cleaned_data[ORDERING_FIELD_NAME]))
174
198
            # After we're done populating self._ordering, sort it.
212
236
        return self._errors
213
237
    errors = property(_get_errors)
214
238
 
 
239
    def _should_delete_form(self, form):
 
240
        # The way we lookup the value of the deletion field here takes
 
241
        # more code than we'd like, but the form's cleaned_data will
 
242
        # not exist if the form is invalid.
 
243
        field = form.fields[DELETION_FIELD_NAME]
 
244
        raw_value = form._raw_value(DELETION_FIELD_NAME)
 
245
        should_delete = field.clean(raw_value)
 
246
        return should_delete
 
247
 
215
248
    def is_valid(self):
216
249
        """
217
250
        Returns True if form.errors is empty for every form in self.forms.
224
257
        for i in range(0, self.total_form_count()):
225
258
            form = self.forms[i]
226
259
            if self.can_delete:
227
 
                # The way we lookup the value of the deletion field here takes
228
 
                # more code than we'd like, but the form's cleaned_data will
229
 
                # not exist if the form is invalid.
230
 
                field = form.fields[DELETION_FIELD_NAME]
231
 
                raw_value = form._raw_value(DELETION_FIELD_NAME)
232
 
                should_delete = field.clean(raw_value)
233
 
                if should_delete:
 
260
                if self._should_delete_form(form):
234
261
                    # This form is going to be deleted so any of its errors
235
262
                    # should not cause the entire formset to be invalid.
236
263
                    continue
252
279
        try:
253
280
            self.clean()
254
281
        except ValidationError, e:
255
 
            self._non_form_errors = e.messages
 
282
            self._non_form_errors = self.error_class(e.messages)
256
283
 
257
284
    def clean(self):
258
285
        """
267
294
        """A hook for adding extra fields on to each form instance."""
268
295
        if self.can_order:
269
296
            # Only pre-fill the ordering field for initial forms.
270
 
            if index < self.initial_form_count():
 
297
            if index is not None and index < self.initial_form_count():
271
298
                form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), initial=index+1, required=False)
272
299
            else:
273
300
                form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), required=False)
302
329
        return mark_safe(u'\n'.join([unicode(self.management_form), forms]))
303
330
 
304
331
def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
305
 
                    can_delete=False, max_num=0):
 
332
                    can_delete=False, max_num=None):
306
333
    """Return a FormSet for the given form class."""
307
334
    attrs = {'form': form, 'extra': extra,
308
335
             'can_order': can_order, 'can_delete': can_delete,