Skip to content

Commit

Permalink
Fixed #35330 -- Fixed the update of related widgets when the referenc…
Browse files Browse the repository at this point in the history
…ed model is camel case named.

Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
  • Loading branch information
devin13cox and nessita committed Apr 3, 2024
1 parent 888b904 commit 8665cf0
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% load i18n static %}
<div class="related-widget-wrapper" {% if not model_has_limit_choices_to %}data-model-ref="{{ model }}"{% endif %}>
<div class="related-widget-wrapper" {% if not model_has_limit_choices_to %}data-model-ref="{{ model_name }}"{% endif %}>
{{ rendered_widget }}
{% block links %}
{% spaceless %}
Expand Down
1 change: 1 addition & 0 deletions django/contrib/admin/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ def get_context(self, name, value, attrs):
"name": name,
"url_params": url_params,
"model": rel_opts.verbose_name,
"model_name": rel_opts.model_name,
"can_add_related": self.can_add_related,
"can_change_related": self.can_change_related,
"can_delete_related": self.can_delete_related,
Expand Down
8 changes: 8 additions & 0 deletions tests/admin_views/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
Book,
Bookmark,
Box,
CamelCaseModel,
CamelCaseRelatedModel,
Category,
Chapter,
ChapterXtra1,
Expand Down Expand Up @@ -1181,6 +1183,10 @@ class SquareAdmin(admin.ModelAdmin):
readonly_fields = ("area",)


class CamelCaseAdmin(admin.ModelAdmin):
filter_horizontal = ["m2m"]


site = admin.AdminSite(name="admin")
site.site_url = "/my-site-url/"
site.register(Article, ArticleAdmin)
Expand Down Expand Up @@ -1305,6 +1311,8 @@ class SquareAdmin(admin.ModelAdmin):
site.register(Country, CountryAdmin)
site.register(Traveler, TravelerAdmin)
site.register(Square, SquareAdmin)
site.register(CamelCaseModel)
site.register(CamelCaseRelatedModel, CamelCaseAdmin)

# Register core models we need in our tests
site.register(User, UserAdmin)
Expand Down
12 changes: 12 additions & 0 deletions tests/admin_views/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,3 +1155,15 @@ class Square(models.Model):

class Meta:
required_db_features = {"supports_stored_generated_columns"}


class CamelCaseModel(models.Model):
interesting_name = models.CharField(max_length=100)

def __str__(self):
return self.interesting_name


class CamelCaseRelatedModel(models.Model):
m2m = models.ManyToManyField(CamelCaseModel, related_name="m2m")
fk = models.ForeignKey(CamelCaseModel, on_delete=models.CASCADE, related_name="fk")
42 changes: 42 additions & 0 deletions tests/admin_views/test_related_object_lookups.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,45 @@ def test_related_object_lookup_link_enabled(self):
with self.subTest(link_id):
link = self.selenium.find_element(By.XPATH, f'//*[@id="{link_id}"]')
self.assertIsNone(link.get_attribute("aria-disabled"))

def test_related_object_update_with_camel_casing(self):
from selenium.webdriver.common.by import By

def _get_HTML_inside_element_by_id(id_):
return self.selenium.find_element(By.ID, id_).get_attribute("innerHTML")

add_url = reverse("admin:admin_views_camelcaserelatedmodel_add")
self.selenium.get(self.live_server_url + add_url)
interesting_name = "A test name"

# Add a new CamelCaseModel using the "+" icon next to the "fk" field.
self.selenium.find_element(By.ID, "add_id_fk").click()

# Switch to the add popup window.
self.wait_for_and_switch_to_popup()

# Find the "interesting_name" field and enter a value, then save it.
self.selenium.find_element(By.ID, "id_interesting_name").send_keys(
interesting_name
)
self.selenium.find_element(By.NAME, "_save").click()

# Return to the main window.
self.wait_until(lambda d: len(d.window_handles) == 1, 1)
self.selenium.switch_to.window(self.selenium.window_handles[0])

# Check that both the "Available" m2m box and the "Fk" dropdown now
# include the newly added CamelCaseModel instance.
self.assertHTMLEqual(
self.selenium.find_element(By.ID, "id_fk"),
f"""
<option value="" selected="">---------</option>
<option value="1" selected>{interesting_name}</option>
""",
)
self.assertHTMLEqual(
self.selenium.find_element(By.ID, "id_m2m_from"),
f"""
<option value="1">{interesting_name}</option>
""",
)
22 changes: 22 additions & 0 deletions tests/admin_widgets/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,28 @@ def test_widget_is_not_hidden(self):
# Related item links are present.
self.assertIn("<a ", output)

def test_data_model_ref_when_model_name_is_camel_case(self):
rel = VideoStream._meta.get_field("release_event").remote_field
widget = forms.Select()
wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site)
self.assertIs(wrapper.is_hidden, False)
context = wrapper.get_context("release_event", None, {})
self.assertEqual(context["model"], "release event")
self.assertEqual(context["model_name"], "releaseevent")
output = wrapper.render("stream", "value")
expected = """
<div class="related-widget-wrapper" data-model-ref="releaseevent">
<select name="stream">
</select>
<a class="related-widget-wrapper-link add-related" id="add_id_stream"
data-popup="yes" title="Add another release event"
href="/admin_widgets/releaseevent/add/?_to_field=album&amp;_popup=1">
<img src="/static/admin/img/icon-addlink.svg" alt="" width="20" height="20">
</a>
</div>
"""
self.assertHTMLEqual(output, expected)


@override_settings(ROOT_URLCONF="admin_widgets.urls")
class AdminWidgetSeleniumTestCase(AdminSeleniumTestCase):
Expand Down

0 comments on commit 8665cf0

Please sign in to comment.