Skip to content

Commit 058ce02

Browse files
author
Jan Schrewe
committed
Cleanup of container widgets and code for LazyDocumentWrapper
1 parent 164ef61 commit 058ce02

File tree

3 files changed

+52
-116
lines changed

3 files changed

+52
-116
lines changed

mongodbforms/documentoptions.py

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def __init__(self, to):
3434

3535
@property
3636
def to(self):
37-
if not isinstance(self._to._meta, DocumentMetaWrapper):
37+
if not isinstance(self._to._meta, (DocumentMetaWrapper, LazyDocumentMetaWrapper)):
3838
self._to._meta = DocumentMetaWrapper(self._to)
3939
return self._to
4040

@@ -72,39 +72,26 @@ def _setup(self):
7272

7373
def __setattr__(self, name, value):
7474
if name in ["_document", "_meta",]:
75-
# Assign to __dict__ to avoid infinite __setattr__ loops.
7675
object.__setattr__(self, name, value)
7776
else:
7877
super(LazyDocumentMetaWrapper, self).__setattr__(name, value)
7978

8079
def __dir__(self):
81-
if self._wrapped is empty:
82-
self._setup()
8380
return self._wrapped.__dir__()
84-
81+
8582
def __getitem__(self, key):
86-
if self._wrapped is empty:
87-
self._setup()
8883
return self._wrapped.__getitem__(key)
8984

9085
def __setitem__(self, key, value):
91-
if self._wrapped is empty:
92-
self._setup()
9386
return self._wrapped.__getitem__(key, value)
9487

9588
def __delitem__(self, key):
96-
if self._wrapped is empty:
97-
self._setup()
9889
return self._wrapped.__delitem__(key)
9990

10091
def __len__(self):
101-
if self._wrapped is empty:
102-
self._setup()
10392
return self._wrapped.__len__()
10493

10594
def __contains__(self, key):
106-
if self._wrapped is empty:
107-
self._setup()
10895
return self._wrapped.__contains__(key)
10996

11097

@@ -185,8 +172,7 @@ def _setup_document_fields(self):
185172
flat.append((choice, value))
186173
f.flatchoices = flat
187174
if isinstance(f, ReferenceField) and not \
188-
isinstance(f.document_type._meta, DocumentMetaWrapper) and not \
189-
isinstance(f.document_type._meta, LazyDocumentMetaWrapper) and \
175+
isinstance(f.document_type._meta, (DocumentMetaWrapper, LazyDocumentMetaWrapper)) and \
190176
self.document != f.document_type:
191177
f.document_type._meta = LazyDocumentMetaWrapper(f.document_type)
192178

@@ -221,7 +207,7 @@ def verbose_name(self):
221207
Returns the verbose name of the document.
222208
223209
Checks the original meta dict first. If it is not found
224-
then generates a verbose name from from the object name.
210+
then generates a verbose name from the object name.
225211
"""
226212
if self._verbose_name is None:
227213
verbose_name = self._meta.get('verbose_name', self.object_name)

mongodbforms/util.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ def load_field_generator():
5050

5151

5252
def init_document_options(document):
53-
if not (isinstance(document._meta, DocumentMetaWrapper) or
54-
isinstance(document._meta, LazyDocumentMetaWrapper)):
53+
if not isinstance(document._meta, (DocumentMetaWrapper, LazyDocumentMetaWrapper)):
5554
document._meta = DocumentMetaWrapper(document)
5655
return document
5756

mongodbforms/widgets.py

Lines changed: 47 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,47 @@ def __init__(self, attrs=None, date_format=None, time_format=None):
1818
MultiWidget.__init__(self, widgets, attrs)
1919

2020

21-
class ListWidget(Widget):
22-
def __init__(self, contained_widget, attrs=None):
23-
self.contained_widget = contained_widget
24-
if isinstance(contained_widget, type):
25-
self.contained_widget = self.contained_widget()
26-
if self.is_localized:
27-
self.widget.is_localized = self.is_localized
28-
super(ListWidget, self).__init__(attrs)
21+
class BaseContainerWidget(Widget):
22+
def __init__(self, data_widget, attrs=None):
23+
if isinstance(data_widget, type):
24+
data_widget = data_widget()
25+
self.data_widget = data_widget
26+
self.data_widget.is_localized = self.is_localized
27+
super(BaseContainerWidget, self).__init__(attrs)
28+
29+
def id_for_label(self, id_):
30+
# See the comment for RadioSelect.id_for_label()
31+
if id_:
32+
id_ += '_0'
33+
return id_
34+
35+
def format_output(self, rendered_widgets):
36+
"""
37+
Given a list of rendered widgets (as strings), returns a Unicode string
38+
representing the HTML for the whole lot.
39+
40+
This hook allows you to format the HTML design of the widgets, if
41+
needed.
42+
"""
43+
return ''.join(rendered_widgets)
2944

45+
def _get_media(self):
46+
"""
47+
Media for a multiwidget is the combination of all media of
48+
the subwidgets.
49+
"""
50+
media = Media()
51+
media = media + self.data_widget.media
52+
return media
53+
media = property(_get_media)
54+
55+
def __deepcopy__(self, memo):
56+
obj = super(BaseContainerWidget, self).__deepcopy__(memo)
57+
obj.data_widget = copy.deepcopy(self.data_widget)
58+
return obj
59+
60+
61+
class ListWidget(BaseContainerWidget):
3062
def render(self, name, value, attrs=None):
3163
if value is not None and not isinstance(value, (list, tuple)):
3264
raise TypeError(
@@ -41,19 +73,13 @@ def render(self, name, value, attrs=None):
4173
for i, widget_value in enumerate(value):
4274
if id_:
4375
final_attrs = dict(final_attrs, id='%s_%s' % (id_, i))
44-
output.append(self.contained_widget.render(
76+
output.append(self.data_widget.render(
4577
name + '_%s' % i, widget_value, final_attrs)
4678
)
4779
return mark_safe(self.format_output(output))
4880

49-
def id_for_label(self, id_):
50-
# See the comment for RadioSelect.id_for_label()
51-
if id_:
52-
id_ += '_0'
53-
return id_
54-
5581
def value_from_datadict(self, data, files, name):
56-
widget = self.contained_widget
82+
widget = self.data_widget
5783
i = 0
5884
ret = []
5985
while (name + '_%s' % i) in data or (name + '_%s' % i) in files:
@@ -67,69 +93,12 @@ def value_from_datadict(self, data, files, name):
6793
i = i + 1
6894
return ret
6995

70-
def format_output(self, rendered_widgets):
71-
"""
72-
Given a list of rendered widgets (as strings), returns a Unicode string
73-
representing the HTML for the whole lot.
74-
75-
This hook allows you to format the HTML design of the widgets, if
76-
needed.
77-
"""
78-
return ''.join(rendered_widgets)
79-
80-
def _get_media(self):
81-
"""
82-
Media for a multiwidget is the combination of all media of
83-
the subwidgets
84-
"""
85-
media = Media()
86-
for w in self.widgets:
87-
media = media + w.media
88-
return media
89-
media = property(_get_media)
90-
91-
def __deepcopy__(self, memo):
92-
obj = super(ListWidget, self).__deepcopy__(memo)
93-
obj.contained_widget = copy.deepcopy(self.contained_widget)
94-
#obj.widget_type = copy.deepcopy(self.widget_type)
95-
return obj
96-
97-
98-
class MapWidget(Widget):
99-
"""
100-
A widget that is composed of multiple widgets.
101-
102-
Its render() method is different than other widgets', because it has to
103-
figure out how to split a single value for display in multiple widgets.
104-
The ``value`` argument can be one of two things:
105-
106-
* A list.
107-
* A normal value (e.g., a string) that has been "compressed" from
108-
a list of values.
109-
110-
In the second case -- i.e., if the value is NOT a list -- render() will
111-
first "decompress" the value into a list before rendering it. It does so by
112-
calling the decompress() method, which MultiWidget subclasses must
113-
implement. This method takes a single "compressed" value and returns a
114-
list.
115-
116-
When render() does its HTML rendering, each value in the list is rendered
117-
with the corresponding widget -- the first value is rendered in the first
118-
widget, the second value is rendered in the second widget, etc.
11996

120-
Subclasses may implement format_output(), which takes the list of rendered
121-
widgets and returns a string of HTML that formats them any way you'd like.
122-
123-
You'll probably want to use this class with MultiValueField.
124-
"""
125-
def __init__(self, contained_widget, attrs=None):
97+
class MapWidget(BaseContainerWidget):
98+
def __init__(self, data_widget, attrs=None):
12699
self.key_widget = TextInput()
127100
self.key_widget.is_localized = self.is_localized
128-
if isinstance(contained_widget, type):
129-
contained_widget = contained_widget()
130-
self.data_widget = contained_widget
131-
self.data_widget.is_localized = self.is_localized
132-
super(MapWidget, self).__init__(attrs)
101+
super(MapWidget, self).__init__(data_widget, attrs)
133102

134103
def render(self, name, value, attrs=None):
135104
if value is not None and not isinstance(value, dict):
@@ -167,12 +136,6 @@ def render(self, name, value, attrs=None):
167136
output.append(mark_safe(''.join(group)))
168137
return mark_safe(self.format_output(output))
169138

170-
def id_for_label(self, id_):
171-
# See the comment for RadioSelect.id_for_label()
172-
if id_:
173-
id_ += '_0'
174-
return id_
175-
176139
def value_from_datadict(self, data, files, name):
177140
i = 0
178141
ret = {}
@@ -188,29 +151,17 @@ def value_from_datadict(self, data, files, name):
188151
i = i + 1
189152
return ret
190153

191-
def format_output(self, rendered_widgets):
192-
"""
193-
Given a list of rendered widgets (as strings), returns a Unicode string
194-
representing the HTML for the whole lot.
195-
196-
This hook allows you to format the HTML design of the widgets, if
197-
needed.
198-
"""
199-
return ''.join(rendered_widgets)
200-
201154
def _get_media(self):
202155
"""
203156
Media for a multiwidget is the combination of all media of
204157
the subwidgets.
205158
"""
206-
media = Media()
207-
for w in self.widgets:
208-
media = media + w.media
159+
media = super(MapWidget, self)._get_media()
160+
media = media + self.key_widget.media
209161
return media
210162
media = property(_get_media)
211163

212164
def __deepcopy__(self, memo):
213165
obj = super(MapWidget, self).__deepcopy__(memo)
214166
obj.key_widget = copy.deepcopy(self.key_widget)
215-
obj.data_widget = copy.deepcopy(self.data_widget)
216167
return obj

0 commit comments

Comments
 (0)