Ticket #13023: 13023_full_max_num_patch.diff

File 13023_full_max_num_patch.diff, 35.4 KB (added by Gabriel Hurley, 14 years ago)

Updated: Noticed another place in inlines.js that needed correction. Complete patch to make max_num default to None instead of 0, including tests and docs.

  • AUTHORS

     
    507507    Cheng Zhang
    508508    Glenn Maynard <glenn@zewt.org>
    509509    bthomas
     510    Gabriel Hurley <gabriel@strikeawe.com>
    510511
    511512A big THANK YOU goes to:
    512513
  • django/contrib/admin/media/js/inlines.js

     
    3232                };
    3333                var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
    3434                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;
    3738                $(this).each(function(i) {
    3839                        $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
    3940                });
     
    7778                                // Update number of total forms
    7879                                $(totalForms).val(nextIndex);
    7980                                // 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())) {
    8182                                        addButton.parent().hide();
    8283                                }
    8384                                // The delete button of each row triggers a bunch of other things
     
    9394                                        var forms = $("." + options.formCssClass);
    9495                                        $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
    9596                                        // 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)) {
    9798                                                addButton.parent().show();
    9899                                        }
    99100                                        // 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)});
    22if(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())+
    331,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,
     4b.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,
    55b.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

     
    11791179    fk_name = None
    11801180    formset = BaseInlineFormSet
    11811181    extra = 3
    1182     max_num = 0
     1182    max_num = None
    11831183    template = None
    11841184    verbose_name = None
    11851185    verbose_name_plural = None
  • django/contrib/admin/validation.py

     
    170170    fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True)
    171171
    172172    # 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__)
    178182
    179183    # formset
    180184    if hasattr(cls, 'formset') and not issubclass(cls.formset, BaseModelFormSet):
  • django/contrib/contenttypes/generic.py

     
    337337                                  ct_field="content_type", fk_field="object_id",
    338338                                  fields=None, exclude=None,
    339339                                  extra=3, can_order=False, can_delete=True,
    340                                   max_num=0,
     340                                  max_num=None,
    341341                                  formfield_callback=lambda f: f.formfield()):
    342342    """
    343343    Returns an ``GenericInlineFormSet`` for the given kwargs.
  • django/forms/formsets.py

     
    2525    def __init__(self, *args, **kwargs):
    2626        self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
    2727        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)
    2929        super(ManagementForm, self).__init__(*args, **kwargs)
    3030
    3131class BaseFormSet(StrAndUnicode):
     
    6969        if self.data or self.files:
    7070            return self.management_form.cleaned_data[TOTAL_FORM_COUNT]
    7171        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:
    7479                total_forms = self.max_num
    7580        return total_forms
    7681
     
    8186        else:
    8287            # Use the length of the inital data if it's there, 0 otherwise.
    8388            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:
    8590                initial_forms = self.max_num
    8691        return initial_forms
    8792
     
    324329        return mark_safe(u'\n'.join([unicode(self.management_form), forms]))
    325330
    326331def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
    327                     can_delete=False, max_num=0):
     332                    can_delete=False, max_num=None):
    328333    """Return a FormSet for the given form class."""
    329334    attrs = {'form': form, 'extra': extra,
    330335             'can_order': can_order, 'can_delete': can_delete,
  • django/forms/models.py

     
    448448            if not qs.ordered:
    449449                qs = qs.order_by(self.model._meta.pk.name)
    450450
    451             if self.max_num > 0:
    452                 self._queryset = qs[:self.max_num]
    453             else:
    454                 self._queryset = qs
     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
    455455        return self._queryset
    456456
    457457    def save_new(self, form, commit=True):
     
    649649def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
    650650                         formset=BaseModelFormSet,
    651651                         extra=1, can_delete=False, can_order=False,
    652                          max_num=0, fields=None, exclude=None):
     652                         max_num=None, fields=None, exclude=None):
    653653    """
    654654    Returns a FormSet class for the given Django model class.
    655655    """
     
    799799def inlineformset_factory(parent_model, model, form=ModelForm,
    800800                          formset=BaseInlineFormSet, fk_name=None,
    801801                          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,
    803803                          formfield_callback=lambda f: f.formfield()):
    804804    """
    805805    Returns an ``InlineFormSet`` for the given kwargs.
  • docs/topics/forms/formsets.txt

     
    7171------------------------------------
    7272
    7373The ``max_num`` parameter to ``formset_factory`` gives you the ability to
    74 force the maximum number of forms the formset will display::
     74limit the maximum number of empty forms the formset will display::
    7575
    7676    >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
    7777    >>> formset = ArticleFormset()
     
    8080    <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>
    8181    <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>
    8282
    83 A ``max_num`` value of ``0`` (the default) puts no limit on the number forms
    84 displayed.
     83.. versionchanged:: 1.2
    8584
     85If the value of ``max_num`` is geater than the number of existing related
     86objects, up to ``extra`` additional blank forms will be added to the formset,
     87so long as the total number of forms does not exceed ``max_num``.
     88
     89A ``max_num`` value of ``None`` (the default) puts no limit on the number of
     90forms displayed. Please note that the default value of ``max_num`` was changed
     91from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value.
     92
     93.. versionadded:: 1.2
     94
     95The 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
    8698Formset validation
    8799------------------
    88100
     
    102114    >>> data = {
    103115    ...     'form-TOTAL_FORMS': u'2',
    104116    ...     'form-INITIAL_FORMS': u'0',
    105     ...     'form-MAX_NUM_FORMS': u'0',
     117    ...     'form-MAX_NUM_FORMS': None,
    106118    ...     'form-0-title': u'Test',
    107119    ...     'form-0-pub_date': u'16 June 1904',
    108120    ...     'form-1-title': u'Test',
     
    190202    >>> data = {
    191203    ...     'form-TOTAL_FORMS': u'2',
    192204    ...     'form-INITIAL_FORMS': u'0',
    193     ...     'form-MAX_NUM_FORMS': u'0',
     205    ...     'form-MAX_NUM_FORMS': None,
    194206    ...     'form-0-title': u'Test',
    195207    ...     'form-0-pub_date': u'16 June 1904',
    196208    ...     'form-1-title': u'Test',
     
    249261    >>> data = {
    250262    ...     'form-TOTAL_FORMS': u'3',
    251263    ...     'form-INITIAL_FORMS': u'2',
    252     ...     'form-MAX_NUM_FORMS': u'0',
     264    ...     'form-MAX_NUM_FORMS': None,
    253265    ...     'form-0-title': u'Article #1',
    254266    ...     'form-0-pub_date': u'2008-05-10',
    255267    ...     'form-0-ORDER': u'2',
     
    287299    ... ])
    288300    >>> for form in formset.forms:
    289301    ....    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" />
    291303    <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>
    292304    <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>
    293305    <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>
     
    305317    >>> data = {
    306318    ...     'form-TOTAL_FORMS': u'3',
    307319    ...     'form-INITIAL_FORMS': u'2',
    308     ...     'form-MAX_NUM_FORMS': u'0',
     320    ...     'form-MAX_NUM_FORMS': None,
    309321    ...     'form-0-title': u'Article #1',
    310322    ...     'form-0-pub_date': u'2008-05-10',
    311323    ...     'form-0-DELETE': u'on',
  • docs/topics/forms/modelforms.txt

     
    557557
    558558    >>> formset = AuthorFormSet()
    559559    >>> 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" />
    561561    <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>
    562562    <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
    563563    <option value="" selected="selected">---------</option>
     
    653653Limiting the number of editable objects
    654654---------------------------------------
    655655
     656.. versionchanged:: 1.2
     657
    656658As 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.
    660660
     661``max_num`` does not prevent existing objects from being displayed::
     662
    661663    >>> Author.objects.order_by('name')
    662664    [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]
    663665
    664     >>> AuthorFormSet = modelformset_factory(Author, max_num=2, extra=1)
     666    >>> AuthorFormSet = modelformset_factory(Author, max_num=1)
    665667    >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
    666     >>> formset.initial
    667     [{'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']
    668670
    669 If the value of ``max_num`` is higher than the number of objects returned, up to
    670 ``extra`` additional blank forms will be added to the formset, so long as the
    671 total number of forms does not exceed ``max_num``::
     671If the value of ``max_num`` is geater than the number of existing related
     672objects, up to ``extra`` additional blank forms will be added to the formset,
     673so long as the total number of forms does not exceed ``max_num``::
    672674
    673675    >>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2)
    674676    >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
     
    679681    <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>
    680682    <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>
    681683
     684.. versionchanged:: 1.2
     685
     686A ``max_num`` value of ``None`` (the default) puts no limit on the number of
     687forms displayed.
     688
    682689Using a model formset in a view
    683690-------------------------------
    684691
  • tests/modeltests/model_formsets/models.py

     
    200200>>> data = {
    201201...     'form-TOTAL_FORMS': '3', # the number of forms rendered
    202202...     'form-INITIAL_FORMS': '0', # the number of forms with initial data
    203 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     203...     'form-MAX_NUM_FORMS': None, # the max number of forms
    204204...     'form-0-name': 'Charles Baudelaire',
    205205...     'form-1-name': 'Arthur Rimbaud',
    206206...     'form-2-name': '',
     
    238238>>> data = {
    239239...     'form-TOTAL_FORMS': '3', # the number of forms rendered
    240240...     'form-INITIAL_FORMS': '2', # the number of forms with initial data
    241 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     241...     'form-MAX_NUM_FORMS': None, # the max number of forms
    242242...     'form-0-id': '2',
    243243...     'form-0-name': 'Arthur Rimbaud',
    244244...     'form-1-id': '1',
     
    282282>>> data = {
    283283...     'form-TOTAL_FORMS': '4', # the number of forms rendered
    284284...     'form-INITIAL_FORMS': '3', # the number of forms with initial data
    285 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     285...     'form-MAX_NUM_FORMS': None, # the max number of forms
    286286...     'form-0-id': '2',
    287287...     'form-0-name': 'Arthur Rimbaud',
    288288...     'form-1-id': '1',
     
    312312>>> data = {
    313313...     'form-TOTAL_FORMS': '4', # the number of forms rendered
    314314...     'form-INITIAL_FORMS': '3', # the number of forms with initial data
    315 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     315...     'form-MAX_NUM_FORMS': None, # the max number of forms
    316316...     'form-0-id': '2',
    317317...     'form-0-name': 'Walt Whitman',
    318318...     'form-1-id': '1',
     
    343343>>> data = {
    344344...     'form-TOTAL_FORMS': '2', # the number of forms rendered
    345345...     'form-INITIAL_FORMS': '1', # the number of forms with initial data
    346 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     346...     'form-MAX_NUM_FORMS': None, # the max number of forms
    347347...     'form-0-id': '1',
    348348...     'form-0-name': '2nd Tuesday of the Week Meeting',
    349349...     'form-0-authors': [2, 1, 3, 4],
     
    365365# delete the author we created to allow later tests to continue working.
    366366>>> new_author.delete()
    367367
    368 Test the behavior of max_num with model formsets. It should properly limit
    369 the queryset to reduce the amount of objects being pulled in when not being
    370 used.
     368Test the behavior of max_num with model formsets. It should allow all existing
     369related objects/inlines for a given object to be displayed, but not allow
     370the creation of new inlines beyond max_num.
    371371
    372372>>> qs = Author.objects.order_by('name')
    373373
    374 >>> AuthorFormSet = modelformset_factory(Author, max_num=2)
     374>>> AuthorFormSet = modelformset_factory(Author, max_num=None, extra=3)
    375375>>> formset = AuthorFormSet(queryset=qs)
     376>>> len(formset.extra_forms)
     3773
     378
     379>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=3)
     380>>> formset = AuthorFormSet(queryset=qs)
     381>>> len(formset.extra_forms)
     3821
     383
     384>>> AuthorFormSet = modelformset_factory(Author, max_num=0, extra=3)
     385>>> formset = AuthorFormSet(queryset=qs)
     386>>> len(formset.extra_forms)
     3870
     388
     389>>> AuthorFormSet = modelformset_factory(Author, max_num=None)
     390>>> formset = AuthorFormSet(queryset=qs)
    376391>>> [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']
    378393
    379 >>> AuthorFormSet = modelformset_factory(Author, max_num=3)
     394>>> AuthorFormSet = modelformset_factory(Author, max_num=0)
    380395>>> formset = AuthorFormSet(queryset=qs)
    381396>>> [x.name for x in formset.get_queryset()]
    382397[u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman']
    383398
     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']
    384403
     404
    385405# ModelForm with a custom save method in a formset ###########################
    386406
    387407>>> class PoetForm(forms.ModelForm):
     
    398418>>> data = {
    399419...     'form-TOTAL_FORMS': '3', # the number of forms rendered
    400420...     'form-INITIAL_FORMS': '0', # the number of forms with initial data
    401 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     421...     'form-MAX_NUM_FORMS': None, # the max number of forms
    402422...     'form-0-name': 'Walt Whitman',
    403423...     'form-1-name': 'Charles Baudelaire',
    404424...     'form-2-name': '',
     
    425445>>> data = {
    426446...     'form-TOTAL_FORMS': '1', # the number of forms rendered
    427447...     'form-INITIAL_FORMS': '0', # the number of forms with initial data
    428 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     448...     'form-MAX_NUM_FORMS': None, # the max number of forms
    429449...     'form-0-author_ptr': '',
    430450...     'form-0-name': 'Ernest Hemingway',
    431451...     'form-0-write_speed': '10',
     
    449469>>> data = {
    450470...     'form-TOTAL_FORMS': '2', # the number of forms rendered
    451471...     'form-INITIAL_FORMS': '1', # the number of forms with initial data
    452 ...     'form-MAX_NUM_FORMS': '0', # the max number of forms
     472...     'form-MAX_NUM_FORMS': None, # the max number of forms
    453473...     'form-0-author_ptr': hemingway_id,
    454474...     'form-0-name': 'Ernest Hemingway',
    455475...     'form-0-write_speed': '10',
     
    484504>>> data = {
    485505...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
    486506...     'book_set-INITIAL_FORMS': '0', # the number of forms with initial data
    487 ...     'book_set-MAX_NUM_FORMS': '0', # the max number of forms
     507...     'book_set-MAX_NUM_FORMS': None, # the max number of forms
    488508...     'book_set-0-title': 'Les Fleurs du Mal',
    489509...     'book_set-1-title': '',
    490510...     'book_set-2-title': '',
     
    519539>>> data = {
    520540...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
    521541...     'book_set-INITIAL_FORMS': '1', # the number of forms with initial data
    522 ...     'book_set-MAX_NUM_FORMS': '0', # the max number of forms
     542...     'book_set-MAX_NUM_FORMS': None, # the max number of forms
    523543...     'book_set-0-id': '1',
    524544...     'book_set-0-title': 'Les Fleurs du Mal',
    525545...     'book_set-1-title': 'Les Paradis Artificiels',
     
    546566>>> data = {
    547567...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
    548568...     'book_set-INITIAL_FORMS': '2', # the number of forms with initial data
    549 ...     'book_set-MAX_NUM_FORMS': '0', # the max number of forms
     569...     'book_set-MAX_NUM_FORMS': None, # the max number of forms
    550570...     'book_set-0-id': '1',
    551571...     'book_set-0-title': 'Les Fleurs du Mal',
    552572...     'book_set-1-id': '2',
     
    584604>>> data = {
    585605...     'bookwithcustompk_set-TOTAL_FORMS': '1', # the number of forms rendered
    586606...     'bookwithcustompk_set-INITIAL_FORMS': '0', # the number of forms with initial data
    587 ...     'bookwithcustompk_set-MAX_NUM_FORMS': '0', # the max number of forms
     607...     'bookwithcustompk_set-MAX_NUM_FORMS': None, # the max number of forms
    588608...     'bookwithcustompk_set-0-my_pk': '77777',
    589609...     'bookwithcustompk_set-0-title': 'Les Fleurs du Mal',
    590610... }
     
    615635>>> data = {
    616636...     'alternatebook_set-TOTAL_FORMS': '1', # the number of forms rendered
    617637...     'alternatebook_set-INITIAL_FORMS': '0', # the number of forms with initial data
    618 ...     'alternatebook_set-MAX_NUM_FORMS': '0', # the max number of forms
     638...     'alternatebook_set-MAX_NUM_FORMS': None, # the max number of forms
    619639...     'alternatebook_set-0-title': 'Flowers of Evil',
    620640...     'alternatebook_set-0-notes': 'English translation of Les Fleurs du Mal'
    621641... }
     
    644664>>> data = {
    645665...     'poem_set-TOTAL_FORMS': '3', # the number of forms rendered
    646666...     'poem_set-INITIAL_FORMS': '0', # the number of forms with initial data
    647 ...     'poem_set-MAX_NUM_FORMS': '0', # the max number of forms
     667...     'poem_set-MAX_NUM_FORMS': None, # the max number of forms
    648668...     'poem_set-0-name': 'The Cloud in Trousers',
    649669...     'poem_set-1-name': 'I',
    650670...     'poem_set-2-name': '',
     
    673693>>> data = {
    674694...     'book_set-TOTAL_FORMS': '5', # the number of forms rendered
    675695...     'book_set-INITIAL_FORMS': '3', # the number of forms with initial data
    676 ...     'book_set-MAX_NUM_FORMS': '0', # the max number of forms
     696...     'book_set-MAX_NUM_FORMS': None, # the max number of forms
    677697...     'book_set-0-id': '1',
    678698...     'book_set-0-title': 'Les Fleurs du Mal',
    679699...     'book_set-1-id': '2',
     
    697717>>> data = {
    698718...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
    699719...     'book_set-INITIAL_FORMS': '1', # the number of forms with initial data
    700 ...     'book_set-MAX_NUM_FORMS': '0', # the max number of forms
     720...     'book_set-MAX_NUM_FORMS': None, # the max number of forms
    701721...     'book_set-0-id': '5',
    702722...     'book_set-0-title': 'Flowers of Evil',
    703723...     'book_set-1-title': 'Revue des deux mondes',
     
    734754>>> data = {
    735755...     'owner_set-TOTAL_FORMS': '2',
    736756...     'owner_set-INITIAL_FORMS': '0',
    737 ...     'owner_set-MAX_NUM_FORMS': '0',
     757...     'owner_set-MAX_NUM_FORMS': None,
    738758...     'owner_set-0-auto_id': '',
    739759...     'owner_set-0-name': u'Joe Perry',
    740760...     'owner_set-1-auto_id': '',
     
    756776>>> data = {
    757777...     'owner_set-TOTAL_FORMS': '3',
    758778...     'owner_set-INITIAL_FORMS': '1',
    759 ...     'owner_set-MAX_NUM_FORMS': '0',
     779...     'owner_set-MAX_NUM_FORMS': None,
    760780...     'owner_set-0-auto_id': u'1',
    761781...     'owner_set-0-name': u'Joe Perry',
    762782...     'owner_set-1-auto_id': '',
     
    848868>>> data = {
    849869...     'form-TOTAL_FORMS': '1',
    850870...     'form-INITIAL_FORMS': '0',
    851 ...     'form-MAX_NUM_FORMS': '0',
     871...     'form-MAX_NUM_FORMS': None,
    852872...     'form-0-slug': 'car-red',
    853873... }
    854874>>> formset = FormSet(data)
     
    860880>>> data = {
    861881...     'form-TOTAL_FORMS': '1',
    862882...     'form-INITIAL_FORMS': '0',
    863 ...     'form-MAX_NUM_FORMS': '0',
     883...     'form-MAX_NUM_FORMS': None,
    864884...     'form-0-slug': 'car-red',
    865885... }
    866886>>> formset = FormSet(data)
     
    875895>>> data = {
    876896...     'form-TOTAL_FORMS': '1',
    877897...     'form-INITIAL_FORMS': '0',
    878 ...     'form-MAX_NUM_FORMS': '0',
     898...     'form-MAX_NUM_FORMS': None,
    879899...     'form-0-price': u'12.00',
    880900...     'form-0-quantity': '1',
    881901... }
     
    888908>>> data = {
    889909...     'form-TOTAL_FORMS': '1',
    890910...     'form-INITIAL_FORMS': '0',
    891 ...     'form-MAX_NUM_FORMS': '0',
     911...     'form-MAX_NUM_FORMS': None,
    892912...     'form-0-price': u'12.00',
    893913...     'form-0-quantity': '1',
    894914... }
     
    906926>>> data = {
    907927...     'revision_set-TOTAL_FORMS': '1',
    908928...     'revision_set-INITIAL_FORMS': '0',
    909 ...     'revision_set-MAX_NUM_FORMS': '0',
     929...     'revision_set-MAX_NUM_FORMS': None,
    910930...     'revision_set-0-repository': repository.pk,
    911931...     'revision_set-0-revision': '146239817507f148d448db38840db7c3cbf47c76',
    912932...     'revision_set-0-DELETE': '',
     
    921941>>> data = {
    922942...     'revision_set-TOTAL_FORMS': '1',
    923943...     'revision_set-INITIAL_FORMS': '0',
    924 ...     'revision_set-MAX_NUM_FORMS': '0',
     944...     'revision_set-MAX_NUM_FORMS': None,
    925945...     'revision_set-0-repository': repository.pk,
    926946...     'revision_set-0-revision': '146239817507f148d448db38840db7c3cbf47c76',
    927947...     'revision_set-0-DELETE': '',
     
    939959>>> data = {
    940960...     'revision_set-TOTAL_FORMS': '1',
    941961...     'revision_set-INITIAL_FORMS': '0',
    942 ...     'revision_set-MAX_NUM_FORMS': '0',
     962...     'revision_set-MAX_NUM_FORMS': None,
    943963...     'revision_set-0-repository': repository.pk,
    944964...     'revision_set-0-revision': '146239817507f148d448db38840db7c3cbf47c76',
    945965...     'revision_set-0-DELETE': '',
     
    969989>>> data = {
    970990...     'membership_set-TOTAL_FORMS': '1',
    971991...     'membership_set-INITIAL_FORMS': '0',
    972 ...     'membership_set-MAX_NUM_FORMS': '0',
     992...     'membership_set-MAX_NUM_FORMS': None,
    973993...     'membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
    974994...     'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
    975995...     'membership_set-0-karma': '',
     
    9841004>>> filled_data = {
    9851005...     'membership_set-TOTAL_FORMS': '1',
    9861006...     'membership_set-INITIAL_FORMS': '0',
    987 ...     'membership_set-MAX_NUM_FORMS': '0',
     1007...     'membership_set-MAX_NUM_FORMS': None,
    9881008...     'membership_set-0-date_joined': unicode(one_day_later.strftime('%Y-%m-%d %H:%M:%S')),
    9891009...     'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
    9901010...     'membership_set-0-karma': '',
     
    10071027>>> data = {
    10081028...     'membership_set-TOTAL_FORMS': '1',
    10091029...     'membership_set-INITIAL_FORMS': '0',
    1010 ...     'membership_set-MAX_NUM_FORMS': '0',
     1030...     'membership_set-MAX_NUM_FORMS': None,
    10111031...     'membership_set-0-date_joined_0': unicode(now.strftime('%Y-%m-%d')),
    10121032...     'membership_set-0-date_joined_1': unicode(now.strftime('%H:%M:%S')),
    10131033...     'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
     
    10431063>>> data = {
    10441064...     'form-TOTAL_FORMS': 2,
    10451065...     'form-INITIAL_FORMS': 0,
    1046 ...     'form-MAX_NUM_FORMS': '0',
     1066...     'form-MAX_NUM_FORMS': None,
    10471067...     'form-0-slug': 'red_car',
    10481068...     'form-1-slug': 'red_car',
    10491069... }
     
    10571077>>> data = {
    10581078...     'form-TOTAL_FORMS': 2,
    10591079...     'form-INITIAL_FORMS': 0,
    1060 ...     'form-MAX_NUM_FORMS': '0',
     1080...     'form-MAX_NUM_FORMS': None,
    10611081...     'form-0-price': '25',
    10621082...     'form-0-quantity': '7',
    10631083...     'form-1-price': '25',
     
    10751095>>> data = {
    10761096...     'form-TOTAL_FORMS': '2',
    10771097...     'form-INITIAL_FORMS': '0',
    1078 ...     'form-MAX_NUM_FORMS': '0',
     1098...     'form-MAX_NUM_FORMS': None,
    10791099...     'form-0-price': '24',
    10801100...     'form-1-price': '24',
    10811101... }
     
    10891109>>> data = {
    10901110...     'book_set-TOTAL_FORMS': '2',
    10911111...     'book_set-INITIAL_FORMS': '2',
    1092 ...     'book_set-MAX_NUM_FORMS': '0',
     1112...     'book_set-MAX_NUM_FORMS': None,
    10931113...
    10941114...     'book_set-0-title': 'The 2008 Election',
    10951115...     'book_set-0-author': str(author.id),
     
    11111131>>> data = {
    11121132...     'form-TOTAL_FORMS': '2',
    11131133...     'form-INITIAL_FORMS': '0',
    1114 ...     'form-MAX_NUM_FORMS': '0',
     1134...     'form-MAX_NUM_FORMS': None,
    11151135...
    11161136...     'form-0-title': 'blah',
    11171137...     'form-0-slug': 'Morning',
     
    11331153>>> data = {
    11341154...     'form-TOTAL_FORMS': '2',
    11351155...     'form-INITIAL_FORMS': '0',
    1136 ...     'form-MAX_NUM_FORMS': '0',
     1156...     'form-MAX_NUM_FORMS': None,
    11371157...
    11381158...     'form-0-title': 'foo',
    11391159...     'form-0-slug': 'Morning in Prague',
     
    11531173>>> data = {
    11541174...     'form-TOTAL_FORMS': '2',
    11551175...     'form-INITIAL_FORMS': '0',
    1156 ...     'form-MAX_NUM_FORMS': '0',
     1176...     'form-MAX_NUM_FORMS': None,
    11571177...
    11581178...     'form-0-title': 'foo',
    11591179...     'form-0-slug': 'Morning in Prague',
  • tests/regressiontests/forms/formsets.py

     
    2020
    2121>>> formset = ChoiceFormSet(auto_id=False, prefix='choices')
    2222>>> 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" />
    2424<tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr>
    2525<tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr>
    2626
  • tests/regressiontests/modeladmin/models.py

     
    919919>>> validate(ValidationTestModelAdmin, ValidationTestModel)
    920920Traceback (most recent call last):
    921921...
    922 ImproperlyConfigured: 'ValidationTestInline.max_num' should be a integer.
     922ImproperlyConfigured: 'ValidationTestInline.max_num' should be an integer or None (default).
    923923
    924924>>> class ValidationTestInline(TabularInline):
    925925...     model = ValidationTestInlineModel
Back to Top