Skip to content

Commit 009d66c

Browse files
committed
fix crash when rendering an invalid form with nested embedded model fields
1 parent 332f70c commit 009d66c

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

django_mongodb_backend/forms/fields/embedded_model.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,12 @@ def bound_data(self, data, initial):
7070
return initial
7171
# Transform the bound data into a model instance.
7272
return self.compress(data)
73+
74+
def prepare_value(self, value):
75+
# When rendering a form with errors, nested EmbeddedModelField data
76+
# won't be compressed if MultiValueField.clean() raises ValidationError
77+
# error before compress() is called. The data must be compressed here
78+
# so that EmbeddedModelBoundField.value() returns a model instance
79+
# (rather than a list) for initializing the form in
80+
# EmbeddedModelBoundField.__str__().
81+
return self.compress(value) if isinstance(value, list) else value

tests/model_forms_/test_embedded_model.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,53 @@ def test_some_missing_data(self):
173173
form = BookForm(data, instance=book)
174174
self.assertFalse(form.is_valid())
175175
self.assertEqual(form.errors["publisher"], ["Enter all required values."])
176+
self.assertHTMLEqual(
177+
str(form),
178+
"""
179+
<div>
180+
<label for="id_title">Title:</label>
181+
<input type="text" name="title" value="Learning MongoDB!" maxlength="50"
182+
required id="id_title">
183+
</div>
184+
<div>
185+
<fieldset>
186+
<legend>Publisher:</legend>
187+
<ul class="errorlist">
188+
<li>Enter all required values.</li>
189+
</ul>
190+
<div>
191+
<label for="id_publisher-name">Name:</label>
192+
<input type="text" name="publisher-name" value="Random House!" maxlength="50"
193+
required id="id_publisher-name">
194+
</div>
195+
<div>
196+
<fieldset>
197+
<legend>Address:</legend>
198+
<div>
199+
<label for="id_publisher-address-po_box">PO Box:</label>
200+
<input type="text" name="publisher-address-po_box" maxlength="50"
201+
id="id_publisher-address-po_box">
202+
</div>
203+
<div>
204+
<label for="id_publisher-address-city">City:</label>
205+
<input type="text" name="publisher-address-city" value="New York City"
206+
maxlength="20" required id="id_publisher-address-city">
207+
</div>
208+
<div>
209+
<label for="id_publisher-address-state">State:</label>
210+
<input type="text" name="publisher-address-state" value="NY"
211+
maxlength="2" required id="id_publisher-address-state">
212+
</div>
213+
<div>
214+
<label for="id_publisher-address-zip_code">Zip code:</label>
215+
<input type="number" name="publisher-address-zip_code"
216+
required id="id_publisher-address-zip_code">
217+
</div>
218+
</fieldset>
219+
</div>
220+
</fieldset>
221+
</div>""",
222+
)
176223

177224
def test_invalid_field_data(self):
178225
"""A field's data (state) is too long."""
@@ -196,6 +243,53 @@ def test_invalid_field_data(self):
196243
form.errors["publisher"],
197244
["Ensure this value has at most 2 characters (it has 8)."],
198245
)
246+
self.assertHTMLEqual(
247+
str(form),
248+
"""
249+
<div>
250+
<label for="id_title">Title:</label>
251+
<input type="text" name="title" value="Learning MongoDB!"
252+
maxlength="50" required id="id_title">
253+
</div>
254+
<div>
255+
<fieldset>
256+
<legend>Publisher:</legend>
257+
<ul class="errorlist">
258+
<li>Ensure this value has at most 2 characters (it has 8).</li>
259+
</ul>
260+
<div>
261+
<label for="id_publisher-name">Name:</label>
262+
<input type="text" name="publisher-name" value="Random House!"
263+
maxlength="50" required id="id_publisher-name">
264+
</div>
265+
<div>
266+
<fieldset>
267+
<legend>Address:</legend>
268+
<div>
269+
<label for="id_publisher-address-po_box">PO Box:</label>
270+
<input type="text" name="publisher-address-po_box"
271+
maxlength="50" id="id_publisher-address-po_box">
272+
</div>
273+
<div>
274+
<label for="id_publisher-address-city">City:</label>
275+
<input type="text" name="publisher-address-city" value="New York City"
276+
maxlength="20" required id="id_publisher-address-city">
277+
</div>
278+
<div>
279+
<label for="id_publisher-address-state">State:</label>
280+
<input type="text" name="publisher-address-state" value="TOO LONG"
281+
maxlength="2" required id="id_publisher-address-state">
282+
</div>
283+
<div>
284+
<label for="id_publisher-address-zip_code">Zip code:</label>
285+
<input type="number" name="publisher-address-zip_code" value="10001"
286+
required id="id_publisher-address-zip_code">
287+
</div>
288+
</fieldset>
289+
</div>
290+
</fieldset>
291+
</div>""",
292+
)
199293

200294
def test_all_missing_data(self):
201295
"""An embedded model with all data missing triggers a required error."""

0 commit comments

Comments
 (0)