Skip to content

Commit

Permalink
fix crash when rendering an invalid form with nested embedded model f…
Browse files Browse the repository at this point in the history
…ields
  • Loading branch information
timgraham committed Jan 31, 2025
1 parent 332f70c commit 009d66c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
9 changes: 9 additions & 0 deletions django_mongodb_backend/forms/fields/embedded_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,12 @@ def bound_data(self, data, initial):
return initial
# Transform the bound data into a model instance.
return self.compress(data)

def prepare_value(self, value):
# When rendering a form with errors, nested EmbeddedModelField data
# won't be compressed if MultiValueField.clean() raises ValidationError
# error before compress() is called. The data must be compressed here
# so that EmbeddedModelBoundField.value() returns a model instance
# (rather than a list) for initializing the form in
# EmbeddedModelBoundField.__str__().
return self.compress(value) if isinstance(value, list) else value
94 changes: 94 additions & 0 deletions tests/model_forms_/test_embedded_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,53 @@ def test_some_missing_data(self):
form = BookForm(data, instance=book)
self.assertFalse(form.is_valid())
self.assertEqual(form.errors["publisher"], ["Enter all required values."])
self.assertHTMLEqual(
str(form),
"""
<div>
<label for="id_title">Title:</label>
<input type="text" name="title" value="Learning MongoDB!" maxlength="50"
required id="id_title">
</div>
<div>
<fieldset>
<legend>Publisher:</legend>
<ul class="errorlist">
<li>Enter all required values.</li>
</ul>
<div>
<label for="id_publisher-name">Name:</label>
<input type="text" name="publisher-name" value="Random House!" maxlength="50"
required id="id_publisher-name">
</div>
<div>
<fieldset>
<legend>Address:</legend>
<div>
<label for="id_publisher-address-po_box">PO Box:</label>
<input type="text" name="publisher-address-po_box" maxlength="50"
id="id_publisher-address-po_box">
</div>
<div>
<label for="id_publisher-address-city">City:</label>
<input type="text" name="publisher-address-city" value="New York City"
maxlength="20" required id="id_publisher-address-city">
</div>
<div>
<label for="id_publisher-address-state">State:</label>
<input type="text" name="publisher-address-state" value="NY"
maxlength="2" required id="id_publisher-address-state">
</div>
<div>
<label for="id_publisher-address-zip_code">Zip code:</label>
<input type="number" name="publisher-address-zip_code"
required id="id_publisher-address-zip_code">
</div>
</fieldset>
</div>
</fieldset>
</div>""",
)

def test_invalid_field_data(self):
"""A field's data (state) is too long."""
Expand All @@ -196,6 +243,53 @@ def test_invalid_field_data(self):
form.errors["publisher"],
["Ensure this value has at most 2 characters (it has 8)."],
)
self.assertHTMLEqual(
str(form),
"""
<div>
<label for="id_title">Title:</label>
<input type="text" name="title" value="Learning MongoDB!"
maxlength="50" required id="id_title">
</div>
<div>
<fieldset>
<legend>Publisher:</legend>
<ul class="errorlist">
<li>Ensure this value has at most 2 characters (it has 8).</li>
</ul>
<div>
<label for="id_publisher-name">Name:</label>
<input type="text" name="publisher-name" value="Random House!"
maxlength="50" required id="id_publisher-name">
</div>
<div>
<fieldset>
<legend>Address:</legend>
<div>
<label for="id_publisher-address-po_box">PO Box:</label>
<input type="text" name="publisher-address-po_box"
maxlength="50" id="id_publisher-address-po_box">
</div>
<div>
<label for="id_publisher-address-city">City:</label>
<input type="text" name="publisher-address-city" value="New York City"
maxlength="20" required id="id_publisher-address-city">
</div>
<div>
<label for="id_publisher-address-state">State:</label>
<input type="text" name="publisher-address-state" value="TOO LONG"
maxlength="2" required id="id_publisher-address-state">
</div>
<div>
<label for="id_publisher-address-zip_code">Zip code:</label>
<input type="number" name="publisher-address-zip_code" value="10001"
required id="id_publisher-address-zip_code">
</div>
</fieldset>
</div>
</fieldset>
</div>""",
)

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

0 comments on commit 009d66c

Please sign in to comment.