Changeset 5202
- Timestamp:
- 05/12/07 09:42:46 (2 years ago)
- Files:
-
- django/trunk/django/newforms/models.py (modified) (6 diffs)
- django/trunk/docs/newforms.txt (modified) (1 diff)
- django/trunk/tests/modeltests/model_forms/models.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/newforms/models.py
r4878 r5202 13 13 'ModelChoiceField', 'ModelMultipleChoiceField') 14 14 15 def model_save(self, commit=True): 16 """ 17 Creates and returns model instance according to self.clean_data. 18 19 This method is created for any form_for_model Form. 20 """ 21 if self.errors: 22 raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name) 23 return save_instance(self, self._model(), commit) 24 25 def save_instance(form, instance, commit=True): 15 def save_instance(form, instance, fields=None, fail_message='saved', commit=True): 26 16 """ 27 17 Saves bound Form ``form``'s clean_data into model instance ``instance``. … … 34 24 opts = instance.__class__._meta 35 25 if form.errors: 36 raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)26 raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message)) 37 27 clean_data = form.clean_data 38 28 for f in opts.fields: 39 29 if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data: 30 continue 31 if fields and f.name not in fields: 40 32 continue 41 33 setattr(instance, f.name, clean_data[f.name]) … … 43 35 instance.save() 44 36 for f in opts.many_to_many: 37 if fields and f.name not in fields: 38 continue 45 39 if f.name in clean_data: 46 40 setattr(instance, f.attname, clean_data[f.name]) … … 51 45 return instance 52 46 53 def make_ instance_save(instance):54 "Returns the save() method for a form_for_instanceForm."47 def make_model_save(model, fields, fail_message): 48 "Returns the save() method for a Form." 55 49 def save(self, commit=True): 56 return save_instance(self, instance, commit) 50 return save_instance(self, model(), fields, fail_message, commit) 51 return save 52 53 def make_instance_save(instance, fields, fail_message): 54 "Returns the save() method for a Form." 55 def save(self, commit=True): 56 return save_instance(self, instance, fields, fail_message, commit) 57 57 return save 58 58 59 def form_for_model(model, form=BaseForm, f ormfield_callback=lambda f: f.formfield()):59 def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda f: f.formfield()): 60 60 """ 61 61 Returns a Form class for the given Django model class. … … 72 72 if not f.editable: 73 73 continue 74 if fields and not f.name in fields: 75 continue 74 76 formfield = formfield_callback(f) 75 77 if formfield: 76 78 field_list.append((f.name, formfield)) 77 fields = SortedDictFromList(field_list) 78 return type(opts.object_name + 'Form', (form,), {'base_fields': fields, '_model': model, 'save': model_save}) 79 base_fields = SortedDictFromList(field_list) 80 return type(opts.object_name + 'Form', (form,), 81 {'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')}) 79 82 80 def form_for_instance(instance, form=BaseForm, f ormfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):83 def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): 81 84 """ 82 85 Returns a Form class for the given Django model instance. … … 95 98 if not f.editable: 96 99 continue 100 if fields and not f.name in fields: 101 continue 97 102 current_value = f.value_from_object(instance) 98 103 formfield = formfield_callback(f, initial=current_value) 99 104 if formfield: 100 105 field_list.append((f.name, formfield)) 101 fields = SortedDictFromList(field_list)106 base_fields = SortedDictFromList(field_list) 102 107 return type(opts.object_name + 'InstanceForm', (form,), 103 {'base_fields': fields, '_model': model, 'save': make_instance_save(instance)})108 {'base_fields': base_fields, '_model': model, 'save': make_instance_save(instance, fields, 'changed')}) 104 109 105 110 def form_for_fields(field_list): django/trunk/docs/newforms.txt
r4819 r5202 871 871 ``help_text``). 872 872 873 Generating forms for models 874 =========================== 875 876 Although you can build customized forms by specifying the fields manually, 877 in many cases you won't need to. Django provides helper methods to simplify the 878 common cases of form creation. 879 880 ``form_for_model()`` 881 -------------------- 882 883 This method creates a form based upon the definition for a specific model. 884 ``form_for_model()`` examines the model definition, and creates a new form 885 class that contains a form field for each model field that is defined. 886 887 The type of fields produced on the generated form is determined by the type 888 of the model fields. For example, a ``CharField`` on a model will be 889 represented with a ``CharField`` on the form. Each ``ManyToManyField`` 890 on the model will be represented with a ``MultipleChoiceField`` on the 891 form. Each ``ForeignKey`` will be represented with a ``ChoiceField``. 892 A ``ChoiceField`` is also used for any model field that has a ``choices`` 893 attribute specified. 894 895 ``form_for_model()`` returns a generated class. This class must then be 896 instantiated:: 897 898 # Create the form class 899 >>> ArticleForm = form_for_model(Article) 900 901 # Create an empty form instance 902 >>> f = ArticleForm() 903 904 The form produced by ``form_for_model`` also has a ``save()`` method. Once the 905 form contains valid data, the ``save()`` method can be used to create a model 906 instance with the attribute values described on the form:: 907 908 # Create a form instance populated with POST data 909 >>> f = ArticleForm(request.POST) 910 911 # Save the new instance 912 >>> new_article = f.save() 913 914 Using an alternate base class 915 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 916 917 If you want to add other methods to the generated form, you can put those 918 methods onto a base class, and instruct ``form_for_model()`` to use that 919 base class. 920 921 By default, every form produced by ``form_for_model()`` extends 922 ``django.newforms.forms.BaseForm``. However, if you provide a ``forms`` 923 argument to ``form_for_model()``, Django will use that class as the base 924 for the form it generates:: 925 926 # Create the new base class: 927 >>> class MyBase(BaseForm): 928 ... def fiddle(self): 929 ... # Do whatever the method does 930 931 # Create the form class with a different base class 932 >>> ArticleForm = form_for_model(Article, form=MyBase) 933 934 # Instantiate the form 935 >>> f = ArticleForm() 936 937 # Use the base class method 938 >>> f.fiddle() 939 940 Putting a subset of fields on the form 941 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 942 **New in Django development version** 943 944 In some cases, you may not want all the model fields to appear on the form. 945 One option is to set ``editable=False`` on the model field. ``form_for_model()`` 946 will not include any non-editable fields on a generated form instance. 947 948 However, if you just want to exclude a field from one specific form, you 949 can use the ``fields`` argument. If you provide a fields argument to 950 ``form_for_model()``, only the fields named will be included on the form. 951 For example, if you only want the 'title' and 'pub_date' attributes to be 952 included on the Article form, you would call:: 953 954 >>> PartialArticleForm = form_for_model(Article, fields=('title', 'pub_date')) 955 956 .. note:: 957 If you specify ``fields`` when creating a form with ``form_for_model()`` 958 make sure that the fields that are *not* specified can provide default 959 values, or are allowed to have a value of ``None``. If a field isn't 960 specified on a form, the object created from the form can't provide 961 a value for that attribute, which will prevent the new instance from 962 being saved. 963 964 Overriding the default field types 965 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 966 967 Although the form field types generated by ``form_for_model()`` are suitable 968 for most general purposes, you may have need to override the default field 969 types on a specific form. In order to do this, ``form_for_model()`` provides 970 access to the *formfield callback*. 971 972 The formfield callback is a function that, when provided with a model field, 973 returns a form field instance. When constructing a form, ``form_for_model()`` 974 asks the formfield callback to provide form field types. The default 975 implementation asks the model field for an appropriate field type; however, 976 any other strategy may be employed. If you need to use an alternate strategy, 977 you can define your own callback, and provide it to ``form_for_model()`` using 978 the ``formfield_callback`` argument. 979 980 For example, if you wanted to use ``MyDateFormField`` for any ``DateField`` 981 fields on the model, you could define the callback:: 982 983 >>> def my_fields(field, **kwargs): 984 ... if isinstance(field, models.DateField): 985 ... return MyDateFormField(**kwargs) 986 ... else: 987 ... return field.formfield(**kwargs) 988 989 >>> ArticleForm = form_for_model(formfield_callback=my_fields) 990 991 Note that your callback needs to handle *all* possible model field types, not 992 just the ones that you want to behave differently to the default. 993 994 Finding the model associated with a form 995 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 996 997 The model class that was used to construct the form is available 998 using the ``_model`` property of the generated form. 999 1000 ``form_for_instance()`` 1001 ----------------------- 1002 1003 ``form_for_instance()`` is very similar to ``form_for_model()``. However, 1004 rather than using a model class to generate a form, it uses an instance of a 1005 model:: 1006 1007 # Create an article 1008 >>> art = Article(... some data ...) 1009 >>> art.save() 1010 1011 # Create a form 1012 >>> ArticleForm = form_for_instance(art) 1013 1014 # Instantiate the form 1015 >>> f = ArticleForm() 1016 1017 When a form created by ``form_for_instance()`` is created, the initial 1018 data values for the form fields are drawn from the instance. However, 1019 this data is not bound to the form. You will need to bind data to the 1020 form before the form can be saved. 1021 1022 When you call ``save()`` on a form created by ``form_for_instance()``, 1023 the database instance will be updated. 1024 1025 ``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback`` 1026 arguments that behave the same way as they do for ``form_for_model()``. 1027 873 1028 More coming soon 874 1029 ================ django/trunk/tests/modeltests/model_forms/models.py
r5119 r5202 180 180 </select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr> 181 181 182 You can restrict a form to a subset of the complete list of fields 183 by providing a 'fields' argument. If you try to save a 184 model created with such a form, you need to ensure that the fields 185 that are _not_ on the form have default values, or are allowed to have 186 a value of None. If a field isn't specified on a form, the object created 187 from the form can't provide a value for that field! 188 >>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date')) 189 >>> f = PartialArticleForm(auto_id=False) 190 >>> print f 191 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> 192 <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> 193 182 194 You can pass a custom Form class to form_for_model. Make sure it's a 183 195 subclass of BaseForm, not Form. … … 225 237 <option value="3">Third test</option> 226 238 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> 227 >>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 'writer': u'1', 'article': 'Hello.'}) 239 >>> f = TestArticleForm({'headline': u'Test headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) 240 >>> f.is_valid() 241 True 242 >>> test_art = f.save() 243 >>> test_art.id 244 1 245 >>> test_art = Article.objects.get(id=1) 246 >>> test_art.headline 247 'Test headline' 248 249 You can create a form over a subset of the available fields 250 by specifying a 'fields' argument to form_for_instance. 251 >>> PartialArticleForm = form_for_instance(art, fields=('headline','pub_date')) 252 >>> f = PartialArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04'}, auto_id=False) 253 >>> print f.as_ul() 254 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> 255 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> 228 256 >>> f.is_valid() 229 257 True
