Ticket #6162: modelform-init-2.diff

File modelform-init-2.diff, 17.2 KB (added by James Bennett, 16 years ago)

Updated patch

  • django/newforms/models.py

     
    262262        return type.__new__(cls, name, bases, attrs)
    263263
    264264class BaseModelForm(BaseForm):
    265     def __init__(self, instance, data=None, files=None, auto_id='id_%s', prefix=None,
    266                  initial=None, error_class=ErrorList, label_suffix=':'):
    267         self.instance = instance
     265    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
     266                 initial=None, error_class=ErrorList, label_suffix=':', instance=None):
    268267        opts = self._meta
    269         object_data = model_to_dict(instance, opts.fields, opts.exclude)
     268        if instance is None and opts.model is None:
     269            raise ImproperlyConfigured("ModelForm must either be bound to a model class or receive a model instance in __init__()")
     270        if instance is None:
     271           self.instance = opts.model()
     272           object_data = {}
     273        else:
     274            self.instance = instance
     275            object_data = model_to_dict(instance, opts.fields, opts.exclude)
    270276        # if initial was provided, it should override the values from instance
    271277        if initial is not None:
    272278            object_data.update(initial)
  • tests/modeltests/model_forms/models.py

     
    2929    def __unicode__(self):
    3030        return self.name
    3131
     32class Editor(models.Model):
     33    name = models.CharField(max_length=50, help_text='Use both first and last names.')
     34    categories = models.ManyToManyField(Category)
     35
     36    def __unicode__(self):
     37        return self.name
     38
    3239class Article(models.Model):
    3340    headline = models.CharField(max_length=50)
    3441    slug = models.SlugField()
     
    155162...
    156163ImproperlyConfigured: BadForm's base classes define more than one model.
    157164
     165Require either a model bound in Meta or an instance passed in on __init__().
    158166
    159 # Old form_for_x tests #######################################################
     167>>> class NoModelForm(ModelForm):
     168...     pass
    160169
     170>>> f = NoModelForm()
     171Traceback (most recent call last):
     172...
     173ImproperlyConfigured: ModelForm must either be bound to a model class or receive a model instance in __init__()
     174
     175# Test valid ModelForms #######################################################
     176
    161177>>> from django.newforms import ModelForm, CharField
    162178>>> import datetime
    163179
     
    167183>>> class CategoryForm(ModelForm):
    168184...     class Meta:
    169185...         model = Category
    170 >>> f = CategoryForm(Category())
     186>>> f = CategoryForm()
    171187>>> print f
    172188<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
    173189<tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
     
    179195>>> print f['name']
    180196<input id="id_name" type="text" name="name" maxlength="20" />
    181197
    182 >>> f = CategoryForm(Category(), auto_id=False)
     198>>> f = CategoryForm(auto_id=False)
    183199>>> print f.as_ul()
    184200<li>Name: <input type="text" name="name" maxlength="20" /></li>
    185201<li>Slug: <input type="text" name="slug" maxlength="20" /></li>
    186202<li>The URL: <input type="text" name="url" maxlength="40" /></li>
    187203
    188 >>> f = CategoryForm(Category(), {'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})
     204>>> f = CategoryForm({'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})
    189205>>> f.is_valid()
    190206True
    191207>>> f.cleaned_data
     
    196212>>> Category.objects.all()
    197213[<Category: Entertainment>]
    198214
    199 >>> f = CategoryForm(Category(), {'name': "It's a test", 'slug': 'its-test', 'url': 'test'})
     215>>> f = CategoryForm({'name': "It's a test", 'slug': 'its-test', 'url': 'test'})
    200216>>> f.is_valid()
    201217True
    202218>>> f.cleaned_data
     
    210226If you call save() with commit=False, then it will return an object that
    211227hasn't yet been saved to the database. In this case, it's up to you to call
    212228save() on the resulting model instance.
    213 >>> f = CategoryForm(Category(), {'name': 'Third test', 'slug': 'third-test', 'url': 'third'})
     229>>> f = CategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'})
    214230>>> f.is_valid()
    215231True
    216232>>> f.cleaned_data
     
    225241[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
    226242
    227243If you call save() with invalid data, you'll get a ValueError.
    228 >>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'})
     244>>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'})
    229245>>> f.errors
    230246{'name': [u'This field is required.'], 'slug': [u'This field is required.']}
    231247>>> f.cleaned_data
     
    236252Traceback (most recent call last):
    237253...
    238254ValueError: The Category could not be created because the data didn't validate.
    239 >>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'})
     255>>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'})
    240256>>> f.save()
    241257Traceback (most recent call last):
    242258...
     
    253269>>> class ArticleForm(ModelForm):
    254270...     class Meta:
    255271...         model = Article
    256 >>> f = ArticleForm(Article(), auto_id=False)
     272>>> f = ArticleForm(auto_id=False)
    257273>>> print f
    258274<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
    259275<tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr>
     
    286302...     class Meta:
    287303...         model = Article
    288304...         fields = ('headline','pub_date')
    289 >>> f = PartialArticleForm(Article(), auto_id=False)
     305>>> f = PartialArticleForm(auto_id=False)
    290306>>> print f
    291307<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
    292308<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
    293309
    294 Use form_for_instance to create a Form from a model instance. The difference
    295 between this Form and one created via form_for_model is that the object's
     310Pass the "instance" keyword argument to create a Form from a model instance. The
     311difference between this Form and one created wthout the"instance" argument is that the object's
    296312current values are inserted as 'initial' data in each Field.
    297313>>> w = Writer.objects.get(name='Mike Royko')
    298314>>> class RoykoForm(ModelForm):
    299315...     class Meta:
    300316...         model = Writer
    301 >>> f = RoykoForm(w, auto_id=False)
     317>>> f = RoykoForm(auto_id=False, instance=w)
    302318>>> print f
    303319<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr>
    304320
     
    309325>>> class TestArticleForm(ModelForm):
    310326...     class Meta:
    311327...         model = Article
    312 >>> f = TestArticleForm(art, auto_id=False)
     328>>> f = TestArticleForm(instance=art, auto_id=False)
    313329>>> print f.as_ul()
    314330<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
    315331<li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li>
     
    331347<option value="2">It&#39;s a test</option>
    332348<option value="3">Third test</option>
    333349</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
    334 >>> f = TestArticleForm(art, {'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'})
     350>>> f = TestArticleForm({'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}, instance=art)
    335351>>> f.is_valid()
    336352True
    337353>>> test_art = f.save()
     
    347363...     class Meta:
    348364...         model = Article
    349365...         fields=('headline', 'slug', 'pub_date')
    350 >>> f = PartialArticleForm(art, {'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False)
     366>>> f = PartialArticleForm({'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False, instance=art)
    351367>>> print f.as_ul()
    352368<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
    353369<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
     
    370386>>> class TestArticleForm(ModelForm):
    371387...     class Meta:
    372388...         model = Article
    373 >>> f = TestArticleForm(new_art, auto_id=False)
     389>>> f = TestArticleForm(auto_id=False, instance=new_art)
    374390>>> print f.as_ul()
    375391<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
    376392<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
     
    393409<option value="3">Third test</option>
    394410</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
    395411
    396 >>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
    397 ...     'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']})
     412>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
     413...     'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}, instance=new_art)
    398414>>> new_art = f.save()
    399415>>> new_art.id
    4004161
     
    403419[<Category: Entertainment>, <Category: It's a test>]
    404420
    405421Now, submit form data with no categories. This deletes the existing categories.
    406 >>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
    407 ...     'writer': u'1', 'article': u'Hello.'})
     422>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
     423...     'writer': u'1', 'article': u'Hello.'}, instance=new_art)
    408424>>> new_art = f.save()
    409425>>> new_art.id
    4104261
     
    416432>>> class ArticleForm(ModelForm):
    417433...     class Meta:
    418434...         model = Article
    419 >>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
     435>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
    420436...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
    421437>>> new_art = f.save()
    422438>>> new_art.id
     
    429445>>> class ArticleForm(ModelForm):
    430446...     class Meta:
    431447...         model = Article
    432 >>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
     448>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
    433449...     'writer': u'1', 'article': u'Test.'})
    434450>>> new_art = f.save()
    435451>>> new_art.id
     
    443459>>> class ArticleForm(ModelForm):
    444460...     class Meta:
    445461...         model = Article
    446 >>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01',
     462>>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01',
    447463...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
    448464>>> new_art = f.save(commit=False)
    449465
     
    474490<Category: Third test>
    475491>>> cat.id
    4764923
    477 >>> form = ShortCategory(cat, {'name': 'Third', 'slug': 'third', 'url': '3rd'})
     493>>> form = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'}, instance=cat)
    478494>>> form.save()
    479495<Category: Third>
    480496>>> Category.objects.get(id=3)
     
    486502>>> class ArticleForm(ModelForm):
    487503...     class Meta:
    488504...         model = Article
    489 >>> f = ArticleForm(Article(), auto_id=False)
     505>>> f = ArticleForm(auto_id=False)
    490506>>> print f.as_ul()
    491507<li>Headline: <input type="text" name="headline" maxlength="50" /></li>
    492508<li>Slug: <input type="text" name="slug" maxlength="50" /></li>
     
    536552<option value="4">Fourth</option>
    537553</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
    538554
     555By not binding the form to a specific model, and by explicitly
     556specifying a list of fields, it's possible to use a ModelForm with any
     557model which has fields of those names. Doing so requires that an
     558instance be passed in on form instantiation.
     559
     560>>> class WriterOrEditorForm(ModelForm):
     561...     name = forms.CharField(max_length=50)
     562>>> w = Writer()
     563>>> f = WriterOrEditorForm(instance=w)
     564>>> print f.as_ul()
     565<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" maxlength="50" /></li>
     566>>> e = Editor(name="Horace Greeley")
     567>>> f = WriterOrEditorForm(instance=e)
     568>>> print f.as_ul()
     569<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="Horace Greeley" maxlength="50" /></li>
     570
     571
    539572# ModelChoiceField ############################################################
    540573
    541574>>> from django.newforms import ModelChoiceField, ModelMultipleChoiceField
     
    690723>>> class PhoneNumberForm(ModelForm):
    691724...     class Meta:
    692725...         model = PhoneNumber
    693 >>> f = PhoneNumberForm(PhoneNumber(), {'phone': '(312) 555-1212', 'description': 'Assistance'})
     726>>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'})
    694727>>> f.is_valid()
    695728True
    696729>>> f.cleaned_data
  • docs/modelforms.txt

     
    2424    ...         model = Article
    2525
    2626    # Creating a form to add an article.
    27     >>> article = Article()
    28     >>> form = ArticleForm(article)
     27    >>> form = ArticleForm()
    2928
    3029    # Creating a form to change an existing article.
    3130    >>> article = Article.objects.get(pk=1)
    32     >>> form = ArticleForm(article)
     31    >>> form = ArticleForm(instance=article)
    3332
    3433Field types
    3534-----------
     
    166165The ``save()`` method
    167166---------------------
    168167
    169 Every form produced by ``ModelForm`` also has a ``save()`` method. This
    170 method creates and saves a database object from the data bound to the form.
    171 A subclass of ``ModelForm`` also requires a model instance as the first
    172 arument to its constructor. For example::
     168Every form produced by ``ModelForm`` also has a ``save()``
     169method. This method creates and saves a database object from the data
     170bound to the form. A subclass of ``ModelForm`` can accept an existing
     171model instance as the keyword argument ``instance``; if this is
     172supplied, ``save()`` will update that instance. If it's not supplied,
     173``save()`` will create a new instance of the specified model::
    173174
    174175    # Create a form instance from POST data.
    175     >>> a = Article()
    176     >>> f = ArticleForm(a, request.POST)
     176    >>> f = ArticleForm(request.POST)
    177177
    178178    # Save a new Article object from the form's data.
    179179    >>> new_article = f.save()
    180180
     181    # Create a form to edit an existing Article.
     182    >>> a = Article.objects.get(pk=1)
     183    >>> f = ArticleForm(instance=a)
     184
    181185Note that ``save()`` will raise a ``ValueError`` if the data in the form
    182186doesn't validate -- i.e., ``if form.errors``.
    183187
     
    201205``save_m2m()`` to save the many-to-many form data. For example::
    202206
    203207    # Create a form instance with POST data.
    204     >>> a = Author()
    205     >>> f = AuthorForm(a, request.POST)
     208    >>> f = AuthorForm(request.POST)
    206209
    207210    # Create, but don't save the new author instance.
    208211    >>> new_author = f.save(commit=False)
     
    222225For example::
    223226
    224227    # Create a form instance with POST data.
    225     >>> a = Author()
    226     >>> f = AuthorForm(a, request.POST)
     228    >>> f = AuthorForm(request.POST)
    227229
    228230    # Create and save the new author instance. There's no need to do anything else.
    229231    >>> new_author = f.save()
     
    277279    manually set anyextra required fields::
    278280   
    279281        instance = Instance(required_field='value')
    280         form = InstanceForm(instance, request.POST)
     282        form = InstanceForm(request.POST, instance=instance)
    281283        new_instance = form.save()
    282284
    283285        instance = form.save(commit=False)
     
    289291
    290292.. _section on saving forms: `The save() method`_
    291293
     294Using a form with any of multiple models
     295----------------------------------------
     296
     297If you have several models which share a common set of fields, and
     298want to expose just those fields for editing, you can define a
     299``ModelForm`` subclass *without* specifying the model, and list only
     300the shared fields to be displayed.
     301
     302For example, if your application has multiple models which represent
     303different types of people, each with a "name" field, you could define
     304a ``ModelForm`` subclass like so::
     305
     306    from django import newforms as forms
     307
     308    class PersonNameForm(forms.ModelForm):
     309        name = forms.CharField(max_length=50)
     310
     311You could then pass any instance of any model which has a "name" field
     312as the ``instance`` keyword argument when creating an instance of the
     313form.
     314
     315Note that when a ``ModelForm`` is used like this, two important
     316restrictions apply:
     317
     3181. Only the fields which are explicitly declared on the form will be
     319   displayed.
     320
     3212. It is your responsibility to supply values for any other required
     322   fields before saving the model instance, either by filling them in
     323   on the instance before passing it to the form, or by using the
     324   ``commit=False`` argument to ``save()`` and then filling in the
     325   fields before actually saving the instance to the databae.
     326       
     327Defining a ``ModelForm`` subclass without specifying a model, and then
     328attempting to instantiate it without passing a model instance as the
     329``instance`` keyword argument, is an error.
     330
     331
    292332Overriding the default field types
    293333----------------------------------
    294334
Back to Top