Ticket #13023: 13023_full_max_num_patch.diff
File 13023_full_max_num_patch.diff, 35.4 KB (added by , 15 years ago) |
---|
-
AUTHORS
507 507 Cheng Zhang 508 508 Glenn Maynard <glenn@zewt.org> 509 509 bthomas 510 Gabriel Hurley <gabriel@strikeawe.com> 510 511 511 512 A big THANK YOU goes to: 512 513 -
django/contrib/admin/media/js/inlines.js
32 32 }; 33 33 var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off"); 34 34 var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off"); 35 // only show the add button if we are allowed to add more items 36 var showAddButton = ((maxForms.val() == 0) || ((maxForms.val()-totalForms.val()) > 0)); 35 // only show the add button if we are allowed to add more items, 36 // note that max_num = None translates to a blank string. 37 var showAddButton = maxForms.val() == '' || (maxForms.val()-totalForms.val()) > 0; 37 38 $(this).each(function(i) { 38 39 $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); 39 40 }); … … 77 78 // Update number of total forms 78 79 $(totalForms).val(nextIndex); 79 80 // Hide add button in case we've hit the max, except we want to add infinitely 80 if ((maxForms.val() != 0) && (maxForms.val() <= totalForms.val())) {81 if ((maxForms.val() != '') && (maxForms.val() <= totalForms.val())) { 81 82 addButton.parent().hide(); 82 83 } 83 84 // The delete button of each row triggers a bunch of other things … … 93 94 var forms = $("." + options.formCssClass); 94 95 $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); 95 96 // Show add button again once we drop below max 96 if ((maxForms.val() == 0) || (maxForms.val() >= forms.length)) {97 if ((maxForms.val() == '') || (maxForms.val() >= forms.length)) { 97 98 addButton.parent().show(); 98 99 } 99 100 // Also, update names and ids for all remaining form controls -
django/contrib/admin/media/js/inlines.min.js
1 (function(a){a.fn.formset=function(f){var b=a.extend({},a.fn.formset.defaults,f),l=function(d,e,j){var c=new RegExp("("+e+"-\\d+)");e=e+"-"+j;a(d).attr("for")&&a(d).attr("for",a(d).attr("for").replace(c,e));if(d.id)d.id=d.id.replace(c,e);if(d.name)d.name=d.name.replace(c,e)};f=a("#id_"+b.prefix+"-TOTAL_FORMS").attr("autocomplete","off");var h=a("#id_"+b.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off");f=h.val()== 0||h.val()-f.val()>0;a(this).each(function(){a(this).not("."+b.emptyCssClass).addClass(b.formCssClass)});1 (function(a){a.fn.formset=function(f){var b=a.extend({},a.fn.formset.defaults,f),l=function(d,e,j){var c=new RegExp("("+e+"-\\d+)");e=e+"-"+j;a(d).attr("for")&&a(d).attr("for",a(d).attr("for").replace(c,e));if(d.id)d.id=d.id.replace(c,e);if(d.name)d.name=d.name.replace(c,e)};f=a("#id_"+b.prefix+"-TOTAL_FORMS").attr("autocomplete","off");var h=a("#id_"+b.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off");f=h.val()==''||h.val()-f.val()>0;a(this).each(function(){a(this).not("."+b.emptyCssClass).addClass(b.formCssClass)}); 2 2 if(a(this).length&&f){var i;if(a(this).attr("tagName")=="TR"){f=this.eq(0).children().length;a(this).parent().append('<tr class="'+b.addCssClass+'"><td colspan="'+f+'"><a href="javascript:void(0)">'+b.addText+"</a></tr>");i=a(this).parent().find("tr:last a")}else{a(this).filter(":last").after('<div class="'+b.addCssClass+'"><a href="javascript:void(0)">'+b.addText+"</a></div>");i=a(this).filter(":last").next().find("a")}i.click(function(){var d=a("#id_"+b.prefix+"-TOTAL_FORMS"),e=parseInt(d.val())+ 3 3 1,j=a("#"+b.prefix+"-empty"),c=j.clone(true).get(0);a(c).removeClass(b.emptyCssClass).removeAttr("id").insertBefore(a(j));a(c).html(a(c).html().replace(/__prefix__/g,e));a(c).addClass(b.formCssClass).attr("id",b.prefix+e);if(a(c).is("TR"))a(c).children(":last").append('<div><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></div>");else a(c).is("UL")||a(c).is("OL")?a(c).append('<li><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></li>"):a(c).children(":first").append('<span><a class="'+ 4 b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></span>");a(c).find("input,select,textarea,label,a").each(function(){l(this,b.prefix,d.val())});a(d).val(e);h.val()!= 0&&h.val()<=d.val()&&i.parent().hide();a(c).find("a."+b.deleteCssClass).click(function(){var g=a(this).parents("."+b.formCssClass);g.remove();b.removed&&b.removed(g);g=a("."+b.formCssClass);a("#id_"+b.prefix+"-TOTAL_FORMS").val(g.length);if(h.val()==0||h.val()>=g.length)i.parent().show();for(var k=0,m=g.length;k<m;k++)a(g.get(k)).find("input,select,textarea,label,a").each(function(){l(this,4 b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></span>");a(c).find("input,select,textarea,label,a").each(function(){l(this,b.prefix,d.val())});a(d).val(e);h.val()!=''&&h.val()<=d.val()&&i.parent().hide();a(c).find("a."+b.deleteCssClass).click(function(){var g=a(this).parents("."+b.formCssClass);g.remove();b.removed&&b.removed(g);g=a("."+b.formCssClass);a("#id_"+b.prefix+"-TOTAL_FORMS").val(g.length);if(h.val()==''||h.val()>=g.length)i.parent().show();for(var k=0,m=g.length;k<m;k++)a(g.get(k)).find("input,select,textarea,label,a").each(function(){l(this, 5 5 b.prefix,k)});return false});b.added&&b.added(a(c));return false})}return this};a.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null}})(jQuery); -
django/contrib/admin/options.py
1179 1179 fk_name = None 1180 1180 formset = BaseInlineFormSet 1181 1181 extra = 3 1182 max_num = 01182 max_num = None 1183 1183 template = None 1184 1184 verbose_name = None 1185 1185 verbose_name_plural = None -
django/contrib/admin/validation.py
170 170 fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True) 171 171 172 172 # extra = 3 173 # max_num = 0 174 for attr in ('extra', 'max_num'): 175 if not isinstance(getattr(cls, attr), int): 176 raise ImproperlyConfigured("'%s.%s' should be a integer." 177 % (cls.__name__, attr)) 173 if not isinstance(getattr(cls, 'extra'), int): 174 raise ImproperlyConfigured("'%s.extra' should be a integer." 175 %cls.__name__) 176 177 # max_num = None 178 max_num = getattr(cls, 'max_num', None) 179 if max_num is not None and not isinstance(max_num, int): 180 raise ImproperlyConfigured("'%s.max_num' should be an integer or None (default)." 181 %cls.__name__) 178 182 179 183 # formset 180 184 if hasattr(cls, 'formset') and not issubclass(cls.formset, BaseModelFormSet): -
django/contrib/contenttypes/generic.py
337 337 ct_field="content_type", fk_field="object_id", 338 338 fields=None, exclude=None, 339 339 extra=3, can_order=False, can_delete=True, 340 max_num= 0,340 max_num=None, 341 341 formfield_callback=lambda f: f.formfield()): 342 342 """ 343 343 Returns an ``GenericInlineFormSet`` for the given kwargs. -
django/forms/formsets.py
25 25 def __init__(self, *args, **kwargs): 26 26 self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput) 27 27 self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput) 28 self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField( widget=HiddenInput)28 self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput) 29 29 super(ManagementForm, self).__init__(*args, **kwargs) 30 30 31 31 class BaseFormSet(StrAndUnicode): … … 69 69 if self.data or self.files: 70 70 return self.management_form.cleaned_data[TOTAL_FORM_COUNT] 71 71 else: 72 total_forms = self.initial_form_count() + self.extra 73 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: 74 79 total_forms = self.max_num 75 80 return total_forms 76 81 … … 81 86 else: 82 87 # Use the length of the inital data if it's there, 0 otherwise. 83 88 initial_forms = self.initial and len(self.initial) or 0 84 if initial_forms > self.max_num > 0:89 if initial_forms > self.max_num >= 0: 85 90 initial_forms = self.max_num 86 91 return initial_forms 87 92 … … 324 329 return mark_safe(u'\n'.join([unicode(self.management_form), forms])) 325 330 326 331 def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, 327 can_delete=False, max_num= 0):332 can_delete=False, max_num=None): 328 333 """Return a FormSet for the given form class.""" 329 334 attrs = {'form': form, 'extra': extra, 330 335 'can_order': can_order, 'can_delete': can_delete, -
django/forms/models.py
448 448 if not qs.ordered: 449 449 qs = qs.order_by(self.model._meta.pk.name) 450 450 451 if self.max_num > 0:452 self._queryset = qs[:self.max_num]453 else:454 451 # Removed queryset limiting here. As per discussion re: #13023 452 # on django-dev, max_num should not prevent existing 453 # related objects/inlines from being displayed. 454 self._queryset = qs 455 455 return self._queryset 456 456 457 457 def save_new(self, form, commit=True): … … 649 649 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(), 650 650 formset=BaseModelFormSet, 651 651 extra=1, can_delete=False, can_order=False, 652 max_num= 0, fields=None, exclude=None):652 max_num=None, fields=None, exclude=None): 653 653 """ 654 654 Returns a FormSet class for the given Django model class. 655 655 """ … … 799 799 def inlineformset_factory(parent_model, model, form=ModelForm, 800 800 formset=BaseInlineFormSet, fk_name=None, 801 801 fields=None, exclude=None, 802 extra=3, can_order=False, can_delete=True, max_num= 0,802 extra=3, can_order=False, can_delete=True, max_num=None, 803 803 formfield_callback=lambda f: f.formfield()): 804 804 """ 805 805 Returns an ``InlineFormSet`` for the given kwargs. -
docs/topics/forms/formsets.txt
71 71 ------------------------------------ 72 72 73 73 The ``max_num`` parameter to ``formset_factory`` gives you the ability to 74 force the maximum number offorms the formset will display::74 limit the maximum number of empty forms the formset will display:: 75 75 76 76 >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1) 77 77 >>> formset = ArticleFormset() … … 80 80 <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr> 81 81 <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr> 82 82 83 A ``max_num`` value of ``0`` (the default) puts no limit on the number forms 84 displayed. 83 .. versionchanged:: 1.2 85 84 85 If the value of ``max_num`` is geater than the number of existing related 86 objects, up to ``extra`` additional blank forms will be added to the formset, 87 so long as the total number of forms does not exceed ``max_num``. 88 89 A ``max_num`` value of ``None`` (the default) puts no limit on the number of 90 forms displayed. Please note that the default value of ``max_num`` was changed 91 from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value. 92 93 .. versionadded:: 1.2 94 95 The dynamic "Add Another" link in the Django admin will not appear if 96 ``max_num`` is less than the number of currently displayed forms. 97 86 98 Formset validation 87 99 ------------------ 88 100 … … 102 114 >>> data = { 103 115 ... 'form-TOTAL_FORMS': u'2', 104 116 ... 'form-INITIAL_FORMS': u'0', 105 ... 'form-MAX_NUM_FORMS': u'0',117 ... 'form-MAX_NUM_FORMS': None, 106 118 ... 'form-0-title': u'Test', 107 119 ... 'form-0-pub_date': u'16 June 1904', 108 120 ... 'form-1-title': u'Test', … … 190 202 >>> data = { 191 203 ... 'form-TOTAL_FORMS': u'2', 192 204 ... 'form-INITIAL_FORMS': u'0', 193 ... 'form-MAX_NUM_FORMS': u'0',205 ... 'form-MAX_NUM_FORMS': None, 194 206 ... 'form-0-title': u'Test', 195 207 ... 'form-0-pub_date': u'16 June 1904', 196 208 ... 'form-1-title': u'Test', … … 249 261 >>> data = { 250 262 ... 'form-TOTAL_FORMS': u'3', 251 263 ... 'form-INITIAL_FORMS': u'2', 252 ... 'form-MAX_NUM_FORMS': u'0',264 ... 'form-MAX_NUM_FORMS': None, 253 265 ... 'form-0-title': u'Article #1', 254 266 ... 'form-0-pub_date': u'2008-05-10', 255 267 ... 'form-0-ORDER': u'2', … … 287 299 ... ]) 288 300 >>> for form in formset.forms: 289 301 .... print form.as_table() 290 <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" value="0"id="id_form-MAX_NUM_FORMS" />302 <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" /> 291 303 <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr> 292 304 <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr> 293 305 <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr> … … 305 317 >>> data = { 306 318 ... 'form-TOTAL_FORMS': u'3', 307 319 ... 'form-INITIAL_FORMS': u'2', 308 ... 'form-MAX_NUM_FORMS': u'0',320 ... 'form-MAX_NUM_FORMS': None, 309 321 ... 'form-0-title': u'Article #1', 310 322 ... 'form-0-pub_date': u'2008-05-10', 311 323 ... 'form-0-DELETE': u'on', -
docs/topics/forms/modelforms.txt
557 557 558 558 >>> formset = AuthorFormSet() 559 559 >>> print formset 560 <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" value="0"id="id_form-MAX_NUM_FORMS" />560 <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" /> 561 561 <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr> 562 562 <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title"> 563 563 <option value="" selected="selected">---------</option> … … 653 653 Limiting the number of editable objects 654 654 --------------------------------------- 655 655 656 .. versionchanged:: 1.2 657 656 658 As with regular formsets, you can use the ``max_num`` parameter to 657 ``modelformset_factory`` to limit the number of forms displayed. With 658 model formsets, this property limits the query to select only the maximum 659 number of objects needed:: 659 ``modelformset_factory`` to limit the number of extra forms displayed. 660 660 661 ``max_num`` does not prevent existing objects from being displayed:: 662 661 663 >>> Author.objects.order_by('name') 662 664 [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>] 663 665 664 >>> AuthorFormSet = modelformset_factory(Author, max_num= 2, extra=1)666 >>> AuthorFormSet = modelformset_factory(Author, max_num=1) 665 667 >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) 666 >>> formset.initial667 [ {'id': 1, 'name': u'Charles Baudelaire'}, {'id': 3, 'name': u'Paul Verlaine'}]668 >>> [x.name for x in formset.get_queryset()] 669 [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman'] 668 670 669 If the value of ``max_num`` is higher than the number of objects returned, up to670 ``extra`` additional blank forms will be added to the formset, so long as the 671 total number of forms does not exceed ``max_num``::671 If the value of ``max_num`` is geater than the number of existing related 672 objects, up to ``extra`` additional blank forms will be added to the formset, 673 so long as the total number of forms does not exceed ``max_num``:: 672 674 673 675 >>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2) 674 676 >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) … … 679 681 <tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr> 680 682 <tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr> 681 683 684 .. versionchanged:: 1.2 685 686 A ``max_num`` value of ``None`` (the default) puts no limit on the number of 687 forms displayed. 688 682 689 Using a model formset in a view 683 690 ------------------------------- 684 691 -
tests/modeltests/model_formsets/models.py
200 200 >>> data = { 201 201 ... 'form-TOTAL_FORMS': '3', # the number of forms rendered 202 202 ... 'form-INITIAL_FORMS': '0', # the number of forms with initial data 203 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms203 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 204 204 ... 'form-0-name': 'Charles Baudelaire', 205 205 ... 'form-1-name': 'Arthur Rimbaud', 206 206 ... 'form-2-name': '', … … 238 238 >>> data = { 239 239 ... 'form-TOTAL_FORMS': '3', # the number of forms rendered 240 240 ... 'form-INITIAL_FORMS': '2', # the number of forms with initial data 241 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms241 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 242 242 ... 'form-0-id': '2', 243 243 ... 'form-0-name': 'Arthur Rimbaud', 244 244 ... 'form-1-id': '1', … … 282 282 >>> data = { 283 283 ... 'form-TOTAL_FORMS': '4', # the number of forms rendered 284 284 ... 'form-INITIAL_FORMS': '3', # the number of forms with initial data 285 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms285 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 286 286 ... 'form-0-id': '2', 287 287 ... 'form-0-name': 'Arthur Rimbaud', 288 288 ... 'form-1-id': '1', … … 312 312 >>> data = { 313 313 ... 'form-TOTAL_FORMS': '4', # the number of forms rendered 314 314 ... 'form-INITIAL_FORMS': '3', # the number of forms with initial data 315 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms315 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 316 316 ... 'form-0-id': '2', 317 317 ... 'form-0-name': 'Walt Whitman', 318 318 ... 'form-1-id': '1', … … 343 343 >>> data = { 344 344 ... 'form-TOTAL_FORMS': '2', # the number of forms rendered 345 345 ... 'form-INITIAL_FORMS': '1', # the number of forms with initial data 346 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms346 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 347 347 ... 'form-0-id': '1', 348 348 ... 'form-0-name': '2nd Tuesday of the Week Meeting', 349 349 ... 'form-0-authors': [2, 1, 3, 4], … … 365 365 # delete the author we created to allow later tests to continue working. 366 366 >>> new_author.delete() 367 367 368 Test the behavior of max_num with model formsets. It should properly limit369 the queryset to reduce the amount of objects being pulled in when not being 370 used.368 Test the behavior of max_num with model formsets. It should allow all existing 369 related objects/inlines for a given object to be displayed, but not allow 370 the creation of new inlines beyond max_num. 371 371 372 372 >>> qs = Author.objects.order_by('name') 373 373 374 >>> AuthorFormSet = modelformset_factory(Author, max_num= 2)374 >>> AuthorFormSet = modelformset_factory(Author, max_num=None, extra=3) 375 375 >>> formset = AuthorFormSet(queryset=qs) 376 >>> len(formset.extra_forms) 377 3 378 379 >>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=3) 380 >>> formset = AuthorFormSet(queryset=qs) 381 >>> len(formset.extra_forms) 382 1 383 384 >>> AuthorFormSet = modelformset_factory(Author, max_num=0, extra=3) 385 >>> formset = AuthorFormSet(queryset=qs) 386 >>> len(formset.extra_forms) 387 0 388 389 >>> AuthorFormSet = modelformset_factory(Author, max_num=None) 390 >>> formset = AuthorFormSet(queryset=qs) 376 391 >>> [x.name for x in formset.get_queryset()] 377 [u'Charles Baudelaire', u'Paul Verlaine' ]392 [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman'] 378 393 379 >>> AuthorFormSet = modelformset_factory(Author, max_num= 3)394 >>> AuthorFormSet = modelformset_factory(Author, max_num=0) 380 395 >>> formset = AuthorFormSet(queryset=qs) 381 396 >>> [x.name for x in formset.get_queryset()] 382 397 [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman'] 383 398 399 >>> AuthorFormSet = modelformset_factory(Author, max_num=4) 400 >>> formset = AuthorFormSet(queryset=qs) 401 >>> [x.name for x in formset.get_queryset()] 402 [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman'] 384 403 404 385 405 # ModelForm with a custom save method in a formset ########################### 386 406 387 407 >>> class PoetForm(forms.ModelForm): … … 398 418 >>> data = { 399 419 ... 'form-TOTAL_FORMS': '3', # the number of forms rendered 400 420 ... 'form-INITIAL_FORMS': '0', # the number of forms with initial data 401 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms421 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 402 422 ... 'form-0-name': 'Walt Whitman', 403 423 ... 'form-1-name': 'Charles Baudelaire', 404 424 ... 'form-2-name': '', … … 425 445 >>> data = { 426 446 ... 'form-TOTAL_FORMS': '1', # the number of forms rendered 427 447 ... 'form-INITIAL_FORMS': '0', # the number of forms with initial data 428 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms448 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 429 449 ... 'form-0-author_ptr': '', 430 450 ... 'form-0-name': 'Ernest Hemingway', 431 451 ... 'form-0-write_speed': '10', … … 449 469 >>> data = { 450 470 ... 'form-TOTAL_FORMS': '2', # the number of forms rendered 451 471 ... 'form-INITIAL_FORMS': '1', # the number of forms with initial data 452 ... 'form-MAX_NUM_FORMS': '0', # the max number of forms472 ... 'form-MAX_NUM_FORMS': None, # the max number of forms 453 473 ... 'form-0-author_ptr': hemingway_id, 454 474 ... 'form-0-name': 'Ernest Hemingway', 455 475 ... 'form-0-write_speed': '10', … … 484 504 >>> data = { 485 505 ... 'book_set-TOTAL_FORMS': '3', # the number of forms rendered 486 506 ... 'book_set-INITIAL_FORMS': '0', # the number of forms with initial data 487 ... 'book_set-MAX_NUM_FORMS': '0', # the max number of forms507 ... 'book_set-MAX_NUM_FORMS': None, # the max number of forms 488 508 ... 'book_set-0-title': 'Les Fleurs du Mal', 489 509 ... 'book_set-1-title': '', 490 510 ... 'book_set-2-title': '', … … 519 539 >>> data = { 520 540 ... 'book_set-TOTAL_FORMS': '3', # the number of forms rendered 521 541 ... 'book_set-INITIAL_FORMS': '1', # the number of forms with initial data 522 ... 'book_set-MAX_NUM_FORMS': '0', # the max number of forms542 ... 'book_set-MAX_NUM_FORMS': None, # the max number of forms 523 543 ... 'book_set-0-id': '1', 524 544 ... 'book_set-0-title': 'Les Fleurs du Mal', 525 545 ... 'book_set-1-title': 'Les Paradis Artificiels', … … 546 566 >>> data = { 547 567 ... 'book_set-TOTAL_FORMS': '3', # the number of forms rendered 548 568 ... 'book_set-INITIAL_FORMS': '2', # the number of forms with initial data 549 ... 'book_set-MAX_NUM_FORMS': '0', # the max number of forms569 ... 'book_set-MAX_NUM_FORMS': None, # the max number of forms 550 570 ... 'book_set-0-id': '1', 551 571 ... 'book_set-0-title': 'Les Fleurs du Mal', 552 572 ... 'book_set-1-id': '2', … … 584 604 >>> data = { 585 605 ... 'bookwithcustompk_set-TOTAL_FORMS': '1', # the number of forms rendered 586 606 ... 'bookwithcustompk_set-INITIAL_FORMS': '0', # the number of forms with initial data 587 ... 'bookwithcustompk_set-MAX_NUM_FORMS': '0', # the max number of forms607 ... 'bookwithcustompk_set-MAX_NUM_FORMS': None, # the max number of forms 588 608 ... 'bookwithcustompk_set-0-my_pk': '77777', 589 609 ... 'bookwithcustompk_set-0-title': 'Les Fleurs du Mal', 590 610 ... } … … 615 635 >>> data = { 616 636 ... 'alternatebook_set-TOTAL_FORMS': '1', # the number of forms rendered 617 637 ... 'alternatebook_set-INITIAL_FORMS': '0', # the number of forms with initial data 618 ... 'alternatebook_set-MAX_NUM_FORMS': '0', # the max number of forms638 ... 'alternatebook_set-MAX_NUM_FORMS': None, # the max number of forms 619 639 ... 'alternatebook_set-0-title': 'Flowers of Evil', 620 640 ... 'alternatebook_set-0-notes': 'English translation of Les Fleurs du Mal' 621 641 ... } … … 644 664 >>> data = { 645 665 ... 'poem_set-TOTAL_FORMS': '3', # the number of forms rendered 646 666 ... 'poem_set-INITIAL_FORMS': '0', # the number of forms with initial data 647 ... 'poem_set-MAX_NUM_FORMS': '0', # the max number of forms667 ... 'poem_set-MAX_NUM_FORMS': None, # the max number of forms 648 668 ... 'poem_set-0-name': 'The Cloud in Trousers', 649 669 ... 'poem_set-1-name': 'I', 650 670 ... 'poem_set-2-name': '', … … 673 693 >>> data = { 674 694 ... 'book_set-TOTAL_FORMS': '5', # the number of forms rendered 675 695 ... 'book_set-INITIAL_FORMS': '3', # the number of forms with initial data 676 ... 'book_set-MAX_NUM_FORMS': '0', # the max number of forms696 ... 'book_set-MAX_NUM_FORMS': None, # the max number of forms 677 697 ... 'book_set-0-id': '1', 678 698 ... 'book_set-0-title': 'Les Fleurs du Mal', 679 699 ... 'book_set-1-id': '2', … … 697 717 >>> data = { 698 718 ... 'book_set-TOTAL_FORMS': '3', # the number of forms rendered 699 719 ... 'book_set-INITIAL_FORMS': '1', # the number of forms with initial data 700 ... 'book_set-MAX_NUM_FORMS': '0', # the max number of forms720 ... 'book_set-MAX_NUM_FORMS': None, # the max number of forms 701 721 ... 'book_set-0-id': '5', 702 722 ... 'book_set-0-title': 'Flowers of Evil', 703 723 ... 'book_set-1-title': 'Revue des deux mondes', … … 734 754 >>> data = { 735 755 ... 'owner_set-TOTAL_FORMS': '2', 736 756 ... 'owner_set-INITIAL_FORMS': '0', 737 ... 'owner_set-MAX_NUM_FORMS': '0',757 ... 'owner_set-MAX_NUM_FORMS': None, 738 758 ... 'owner_set-0-auto_id': '', 739 759 ... 'owner_set-0-name': u'Joe Perry', 740 760 ... 'owner_set-1-auto_id': '', … … 756 776 >>> data = { 757 777 ... 'owner_set-TOTAL_FORMS': '3', 758 778 ... 'owner_set-INITIAL_FORMS': '1', 759 ... 'owner_set-MAX_NUM_FORMS': '0',779 ... 'owner_set-MAX_NUM_FORMS': None, 760 780 ... 'owner_set-0-auto_id': u'1', 761 781 ... 'owner_set-0-name': u'Joe Perry', 762 782 ... 'owner_set-1-auto_id': '', … … 848 868 >>> data = { 849 869 ... 'form-TOTAL_FORMS': '1', 850 870 ... 'form-INITIAL_FORMS': '0', 851 ... 'form-MAX_NUM_FORMS': '0',871 ... 'form-MAX_NUM_FORMS': None, 852 872 ... 'form-0-slug': 'car-red', 853 873 ... } 854 874 >>> formset = FormSet(data) … … 860 880 >>> data = { 861 881 ... 'form-TOTAL_FORMS': '1', 862 882 ... 'form-INITIAL_FORMS': '0', 863 ... 'form-MAX_NUM_FORMS': '0',883 ... 'form-MAX_NUM_FORMS': None, 864 884 ... 'form-0-slug': 'car-red', 865 885 ... } 866 886 >>> formset = FormSet(data) … … 875 895 >>> data = { 876 896 ... 'form-TOTAL_FORMS': '1', 877 897 ... 'form-INITIAL_FORMS': '0', 878 ... 'form-MAX_NUM_FORMS': '0',898 ... 'form-MAX_NUM_FORMS': None, 879 899 ... 'form-0-price': u'12.00', 880 900 ... 'form-0-quantity': '1', 881 901 ... } … … 888 908 >>> data = { 889 909 ... 'form-TOTAL_FORMS': '1', 890 910 ... 'form-INITIAL_FORMS': '0', 891 ... 'form-MAX_NUM_FORMS': '0',911 ... 'form-MAX_NUM_FORMS': None, 892 912 ... 'form-0-price': u'12.00', 893 913 ... 'form-0-quantity': '1', 894 914 ... } … … 906 926 >>> data = { 907 927 ... 'revision_set-TOTAL_FORMS': '1', 908 928 ... 'revision_set-INITIAL_FORMS': '0', 909 ... 'revision_set-MAX_NUM_FORMS': '0',929 ... 'revision_set-MAX_NUM_FORMS': None, 910 930 ... 'revision_set-0-repository': repository.pk, 911 931 ... 'revision_set-0-revision': '146239817507f148d448db38840db7c3cbf47c76', 912 932 ... 'revision_set-0-DELETE': '', … … 921 941 >>> data = { 922 942 ... 'revision_set-TOTAL_FORMS': '1', 923 943 ... 'revision_set-INITIAL_FORMS': '0', 924 ... 'revision_set-MAX_NUM_FORMS': '0',944 ... 'revision_set-MAX_NUM_FORMS': None, 925 945 ... 'revision_set-0-repository': repository.pk, 926 946 ... 'revision_set-0-revision': '146239817507f148d448db38840db7c3cbf47c76', 927 947 ... 'revision_set-0-DELETE': '', … … 939 959 >>> data = { 940 960 ... 'revision_set-TOTAL_FORMS': '1', 941 961 ... 'revision_set-INITIAL_FORMS': '0', 942 ... 'revision_set-MAX_NUM_FORMS': '0',962 ... 'revision_set-MAX_NUM_FORMS': None, 943 963 ... 'revision_set-0-repository': repository.pk, 944 964 ... 'revision_set-0-revision': '146239817507f148d448db38840db7c3cbf47c76', 945 965 ... 'revision_set-0-DELETE': '', … … 969 989 >>> data = { 970 990 ... 'membership_set-TOTAL_FORMS': '1', 971 991 ... 'membership_set-INITIAL_FORMS': '0', 972 ... 'membership_set-MAX_NUM_FORMS': '0',992 ... 'membership_set-MAX_NUM_FORMS': None, 973 993 ... 'membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 974 994 ... 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 975 995 ... 'membership_set-0-karma': '', … … 984 1004 >>> filled_data = { 985 1005 ... 'membership_set-TOTAL_FORMS': '1', 986 1006 ... 'membership_set-INITIAL_FORMS': '0', 987 ... 'membership_set-MAX_NUM_FORMS': '0',1007 ... 'membership_set-MAX_NUM_FORMS': None, 988 1008 ... 'membership_set-0-date_joined': unicode(one_day_later.strftime('%Y-%m-%d %H:%M:%S')), 989 1009 ... 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 990 1010 ... 'membership_set-0-karma': '', … … 1007 1027 >>> data = { 1008 1028 ... 'membership_set-TOTAL_FORMS': '1', 1009 1029 ... 'membership_set-INITIAL_FORMS': '0', 1010 ... 'membership_set-MAX_NUM_FORMS': '0',1030 ... 'membership_set-MAX_NUM_FORMS': None, 1011 1031 ... 'membership_set-0-date_joined_0': unicode(now.strftime('%Y-%m-%d')), 1012 1032 ... 'membership_set-0-date_joined_1': unicode(now.strftime('%H:%M:%S')), 1013 1033 ... 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), … … 1043 1063 >>> data = { 1044 1064 ... 'form-TOTAL_FORMS': 2, 1045 1065 ... 'form-INITIAL_FORMS': 0, 1046 ... 'form-MAX_NUM_FORMS': '0',1066 ... 'form-MAX_NUM_FORMS': None, 1047 1067 ... 'form-0-slug': 'red_car', 1048 1068 ... 'form-1-slug': 'red_car', 1049 1069 ... } … … 1057 1077 >>> data = { 1058 1078 ... 'form-TOTAL_FORMS': 2, 1059 1079 ... 'form-INITIAL_FORMS': 0, 1060 ... 'form-MAX_NUM_FORMS': '0',1080 ... 'form-MAX_NUM_FORMS': None, 1061 1081 ... 'form-0-price': '25', 1062 1082 ... 'form-0-quantity': '7', 1063 1083 ... 'form-1-price': '25', … … 1075 1095 >>> data = { 1076 1096 ... 'form-TOTAL_FORMS': '2', 1077 1097 ... 'form-INITIAL_FORMS': '0', 1078 ... 'form-MAX_NUM_FORMS': '0',1098 ... 'form-MAX_NUM_FORMS': None, 1079 1099 ... 'form-0-price': '24', 1080 1100 ... 'form-1-price': '24', 1081 1101 ... } … … 1089 1109 >>> data = { 1090 1110 ... 'book_set-TOTAL_FORMS': '2', 1091 1111 ... 'book_set-INITIAL_FORMS': '2', 1092 ... 'book_set-MAX_NUM_FORMS': '0',1112 ... 'book_set-MAX_NUM_FORMS': None, 1093 1113 ... 1094 1114 ... 'book_set-0-title': 'The 2008 Election', 1095 1115 ... 'book_set-0-author': str(author.id), … … 1111 1131 >>> data = { 1112 1132 ... 'form-TOTAL_FORMS': '2', 1113 1133 ... 'form-INITIAL_FORMS': '0', 1114 ... 'form-MAX_NUM_FORMS': '0',1134 ... 'form-MAX_NUM_FORMS': None, 1115 1135 ... 1116 1136 ... 'form-0-title': 'blah', 1117 1137 ... 'form-0-slug': 'Morning', … … 1133 1153 >>> data = { 1134 1154 ... 'form-TOTAL_FORMS': '2', 1135 1155 ... 'form-INITIAL_FORMS': '0', 1136 ... 'form-MAX_NUM_FORMS': '0',1156 ... 'form-MAX_NUM_FORMS': None, 1137 1157 ... 1138 1158 ... 'form-0-title': 'foo', 1139 1159 ... 'form-0-slug': 'Morning in Prague', … … 1153 1173 >>> data = { 1154 1174 ... 'form-TOTAL_FORMS': '2', 1155 1175 ... 'form-INITIAL_FORMS': '0', 1156 ... 'form-MAX_NUM_FORMS': '0',1176 ... 'form-MAX_NUM_FORMS': None, 1157 1177 ... 1158 1178 ... 'form-0-title': 'foo', 1159 1179 ... 'form-0-slug': 'Morning in Prague', -
tests/regressiontests/forms/formsets.py
20 20 21 21 >>> formset = ChoiceFormSet(auto_id=False, prefix='choices') 22 22 >>> print formset 23 <input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0"/>23 <input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" /> 24 24 <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr> 25 25 <tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr> 26 26 -
tests/regressiontests/modeladmin/models.py
919 919 >>> validate(ValidationTestModelAdmin, ValidationTestModel) 920 920 Traceback (most recent call last): 921 921 ... 922 ImproperlyConfigured: 'ValidationTestInline.max_num' should be a integer.922 ImproperlyConfigured: 'ValidationTestInline.max_num' should be an integer or None (default). 923 923 924 924 >>> class ValidationTestInline(TabularInline): 925 925 ... model = ValidationTestInlineModel