| Home | Trees | Indices | Help |
|---|
|
|
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (c) 2008-2009 Benoit Chesneau <benoitc@e-engura.com>
4 #
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
8 #
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #
17 # code heavily inspired from django.forms.models
18 # Copyright (c) Django Software Foundation and individual contributors.
19 # All rights reserved.
20 #
21 # Redistribution and use in source and binary forms, with or without modification,
22 # are permitted provided that the following conditions are met:
23 #
24 # 1. Redistributions of source code must retain the above copyright notice,
25 # this list of conditions and the following disclaimer.
26 #
27 # 2. Redistributions in binary form must reproduce the above copyright
28 # notice, this list of conditions and the following disclaimer in the
29 # documentation and/or other materials provided with the distribution.
30 #
31 # 3. Neither the name of Django nor the names of its contributors may be used
32 # to endorse or promote products derived from this software without
33 # specific prior written permission.
34 #
35 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
36 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
37 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
39 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
41 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
42 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
46 """ Implement DocumentForm object. It map Document objects to Form and
47 works like ModelForm object :
48
49 >>> from couchdbkit.ext.django.forms import DocumentForm
50
51 # Create the form class.
52 >>> class ArticleForm(DocumentForm):
53 ... class Meta:
54 ... model = Article
55
56 # Creating a form to add an article.
57 >>> form = ArticleForm()
58
59 # Creating a form to change an existing article.
60 >>> article = Article.get(someid)
61 >>> form = ArticleForm(instance=article)
62
63
64 The generated Form class will have a form field for every model field.
65 Each document property has a corresponding default form field:
66
67 * StringProperty -> CharField,
68 * IntegerProperty -> IntegerField,
69 * DecimalProperty -> DecimalField,
70 * BooleanProperty -> BooleanField,
71 * FloatProperty -> FloatField,
72 * DateTimeProperty -> DateTimeField,
73 * DateProperty -> DateField,
74 * TimeProperty -> TimeField
75
76
77 More fields types will be supported soon.
78 """
79
80
81 from django.utils.text import capfirst
82 from django.utils.datastructures import SortedDict
83 from django.forms.util import ValidationError, ErrorList
84 from django.forms.forms import BaseForm, get_declared_fields
85 from django.forms import fields as f
86 from django.forms.widgets import media_property
87
88 from . import schema
89 from ...schema import value_to_python
90
91 FIELDS_PROPERTES_MAPPING = {
92 "StringProperty": f.CharField,
93 "IntegerProperty": f.IntegerField,
94 "DecimalProperty": f.DecimalField,
95 "BooleanProperty": f.BooleanField,
96 "FloatProperty": f.FloatField,
97 "DateTimeProperty": f.DateTimeField,
98 "DateProperty": f.DateField,
99 "TimeProperty": f.TimeField
100 }
101
103 """
104 Returns a dict containing the data in ``instance`` suitable for passing as
105 a Form's ``initial`` keyword argument.
106
107 ``properties`` is an optional list of properties names. If provided,
108 only the named properties will be included in the returned dict.
109
110 ``exclude`` is an optional list of properties names. If provided, the named
111 properties will be excluded from the returned dict, even if they are listed
112 in the ``properties`` argument.
113 """
114 # avoid a circular import
115 data = {}
116 for prop_name in instance._doc.keys():
117 if properties and not prop_name in properties:
118 continue
119 if exclude and prop_name in exclude:
120 continue
121 data[prop_name] = instance[prop_name]
122 return data
123
125 """
126 Returns a ``SortedDict`` containing form fields for the given document.
127
128 ``properties`` is an optional list of properties names. If provided,
129 only the named properties will be included in the returned properties.
130
131 ``exclude`` is an optional list of properties names. If provided, the named
132 properties will be excluded from the returned properties, even if
133 they are listed in the ``properties`` argument.
134 """
135 field_list = []
136
137 values = []
138 if properties:
139 values = [document._properties[prop] for prop in properties if \
140 prop in document._properties]
141 else:
142 values = document._properties.values()
143 values.sort(lambda a, b: cmp(a.creation_counter, b.creation_counter))
144
145 for prop in values:
146 if properties and not prop.name in properties:
147 continue
148 if exclude and prop.name in exclude:
149 continue
150 property_class_name = prop.__class__.__name__
151 if property_class_name in FIELDS_PROPERTES_MAPPING:
152 defaults = {
153 'required': prop.required,
154 'label': capfirst(prop.verbose_name),
155 }
156
157 if prop.default is not None:
158 defaults['initial'] = prop.default_value
159
160 if prop.choices:
161 if prop.default:
162 defaults['choices'] = prop.default_value() + list(
163 prop.choices)
164 defaults['coerce'] = prop.to_python
165
166 field_list.append((prop.name,
167 FIELDS_PROPERTES_MAPPING[property_class_name](**defaults)))
168 return SortedDict(field_list)
169
172 self.document = getattr(options, 'document', None)
173 self.properties = getattr(options, 'properties', None)
174 self.exclude = getattr(options, 'exclude', None)
175
178 try:
179 parents = [b for b in bases if issubclass(b, DocumentForm)]
180 except NameError:
181 # We are defining ModelForm itself.
182 parents = None
183
184 declared_fields = get_declared_fields(bases, attrs, False)
185 new_class = super(DocumentFormMetaClass, cls).__new__(cls, name, bases,
186 attrs)
187
188 if not parents:
189 return new_class
190
191 if 'media' not in attrs:
192 new_class.media = media_property(new_class)
193
194 opts = new_class._meta = DocumentFormOptions(getattr(new_class,
195 'Meta', None))
196
197 if opts.document:
198 # If a document is defined, extract form fields from it.
199 fields = fields_for_document(opts.document, opts.properties,
200 opts.exclude)
201 # Override default docuemnt fields with any custom declared ones
202 # (plus, include all the other declared fields).
203 fields.update(declared_fields)
204 else:
205 fields = declared_fields
206
207 new_class.declared_fields = declared_fields
208 new_class.base_fields = fields
209 return new_class
210
212 """ Base Document Form object """
213
214 - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
215 initial=None, error_class=ErrorList, label_suffix=":",
216 empty_permitted=False, instance=None):
217
218 opts = self._meta
219
220 if instance is None:
221 self.instance = opts.document()
222 object_data = {}
223 else:
224 self.instance = instance
225 object_data = document_to_dict(instance, opts.properties,
226 opts.exclude)
227
228 if initial is not None:
229 object_data.update(initial)
230
231 super(BaseDocumentForm, self).__init__(data, files, auto_id, prefix,
232 object_data, error_class,
233 label_suffix, empty_permitted)
234
236 """
237 Saves this ``form``'s cleaned_data into document instance
238 ``self.instance``.
239
240 If commit=True, then the changes to ``instance`` will be saved to the
241 database. Returns ``instance``.
242 """
243
244 opts = self._meta
245 cleaned_data = self.cleaned_data.copy()
246 for prop_name in self.instance._doc.keys():
247 if opts.properties and prop_name not in opts.properties:
248 continue
249 if opts.exclude and prop_name in opts.exclude:
250 continue
251 if prop_name in cleaned_data:
252 value = cleaned_data.pop(prop_name)
253 if value is not None:
254 setattr(self.instance, prop_name, value)
255
256 if dynamic:
257 for attr_name in cleaned_data.keys():
258 if opts.exclude and attr_name in opts.exclude:
259 continue
260 value = cleaned_data[attr_name]
261 if value is not None:
262 setattr(self.instance, attr_name, value)
263
264 if commit:
265 self.instance.save()
266
267 return self.instance
268
272
| Home | Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Fri Feb 18 10:31:29 2011 | http://epydoc.sourceforge.net |