Browse Source

Fixed #33267 -- Added link to related item to related widget wrapper in admin.

Shubh1815 3 years ago
parent
commit
11cc227344

+ 2 - 2
django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js

@@ -125,7 +125,7 @@
                 this.textContent = newRepr;
                 this.value = newId;
             }
-        });
+        }).trigger('change');
         selects.next().find('.select2-selection__rendered').each(function() {
             // The element can have a clear button as a child.
             // Use the lastChild to modify only the displayed value.
@@ -178,7 +178,7 @@
             event.preventDefault();
             opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
         });
-        $('body').on('click', '.related-widget-wrapper-link', function(e) {
+        $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) {
             e.preventDefault();
             if (this.href) {
                 const event = $.Event('django:show-related', {href: this.href});

+ 10 - 0
django/contrib/admin/templates/admin/widgets/related_widget_wrapper.html

@@ -7,12 +7,14 @@
         {% if can_change_related %}
         <a class="related-widget-wrapper-link change-related" id="change_id_{{ name }}"
             data-href-template="{{ change_related_template_url }}?{{ url_params }}"
+            data-popup="yes"
             title="{% blocktranslate %}Change selected {{ model }}{% endblocktranslate %}">
             <img src="{% static 'admin/img/icon-changelink.svg' %}" alt="{% translate 'Change' %}">
         </a>
         {% endif %}
         {% if can_add_related %}
         <a class="related-widget-wrapper-link add-related" id="add_id_{{ name }}"
+            data-popup="yes"
             href="{{ add_related_url }}?{{ url_params }}"
             title="{% blocktranslate %}Add another {{ model }}{% endblocktranslate %}">
             <img src="{% static 'admin/img/icon-addlink.svg' %}" alt="{% translate 'Add' %}">
@@ -21,10 +23,18 @@
         {% if can_delete_related %}
         <a class="related-widget-wrapper-link delete-related" id="delete_id_{{ name }}"
             data-href-template="{{ delete_related_template_url }}?{{ url_params }}"
+            data-popup="yes"
             title="{% blocktranslate %}Delete selected {{ model }}{% endblocktranslate %}">
             <img src="{% static 'admin/img/icon-deletelink.svg' %}" alt="{% translate 'Delete' %}">
         </a>
         {% endif %}
+        {% if can_view_related %}
+          <a class="related-widget-wrapper-link view-related" id="view_id_{{ name }}"
+             data-href-template="{{ change_related_template_url }}?{{ view_related_url_params }}"
+             title="{% blocktranslate %}View selected {{ model }}{% endblocktranslate %}">
+            <img src="{% static 'admin/img/icon-viewlink.svg' %}" alt="{% translate 'View' %}">
+          </a>
+        {% endif %}
         {% endif %}
         {% endspaceless %}
     {% endblock %}

+ 3 - 1
django/contrib/admin/widgets.py

@@ -300,10 +300,11 @@ class RelatedFieldWidgetWrapper(forms.Widget):
         rel_opts = self.rel.model._meta
         info = (rel_opts.app_label, rel_opts.model_name)
         self.widget.choices = self.choices
+        related_field_name = self.rel.get_related_field().name
         url_params = "&".join(
             "%s=%s" % param
             for param in [
-                (TO_FIELD_VAR, self.rel.get_related_field().name),
+                (TO_FIELD_VAR, related_field_name),
                 (IS_POPUP_VAR, 1),
             ]
         )
@@ -325,6 +326,7 @@ class RelatedFieldWidgetWrapper(forms.Widget):
                 info, "delete", "__fk__"
             )
         if self.can_view_related or self.can_change_related:
+            context["view_related_url_params"] = f"{TO_FIELD_VAR}={related_field_name}"
             context["change_related_template_url"] = self.get_related_url(
                 info, "change", "__fk__"
             )

BIN
docs/intro/_images/admin09.png


+ 2 - 0
docs/releases/4.1.txt

@@ -61,6 +61,8 @@ Minor features
 * The admin :meth:`history view <django.contrib.admin.ModelAdmin.history_view>`
   is now paginated.
 
+* Related widget wrappers now have a link to object's change form.
+
 :mod:`django.contrib.admindocs`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 13 - 0
tests/admin_widgets/tests.py

@@ -1675,6 +1675,7 @@ class AdminRawIdWidgetSeleniumTests(AdminWidgetSeleniumTestCase):
 class RelatedFieldWidgetSeleniumTests(AdminWidgetSeleniumTestCase):
     def test_ForeignKey_using_to_field(self):
         from selenium.webdriver.common.by import By
+        from selenium.webdriver.support.ui import Select
 
         self.admin_login(username="super", password="secret", login_url="/")
         self.selenium.get(
@@ -1698,6 +1699,12 @@ class RelatedFieldWidgetSeleniumTests(AdminWidgetSeleniumTestCase):
         # The field now contains the new user
         self.selenium.find_element(By.CSS_SELECTOR, "#id_user option[value=newuser]")
 
+        self.selenium.find_element(By.ID, "view_id_user").click()
+        self.wait_for_value("#id_username", "newuser")
+        self.selenium.back()
+
+        select = Select(self.selenium.find_element(By.ID, "id_user"))
+        select.select_by_value("newuser")
         # Click the Change User button to change it
         self.selenium.find_element(By.ID, "change_id_user").click()
         self.wait_for_and_switch_to_popup()
@@ -1714,6 +1721,12 @@ class RelatedFieldWidgetSeleniumTests(AdminWidgetSeleniumTestCase):
             By.CSS_SELECTOR, "#id_user option[value=changednewuser]"
         )
 
+        self.selenium.find_element(By.ID, "view_id_user").click()
+        self.wait_for_value("#id_username", "changednewuser")
+        self.selenium.back()
+
+        select = Select(self.selenium.find_element(By.ID, "id_user"))
+        select.select_by_value("changednewuser")
         # Go ahead and submit the form to make sure it works
         self.selenium.find_element(By.CSS_SELECTOR, save_button_css_selector).click()
         self.wait_for_text(