Commit 65cf82bd authored by Rainer Koirikivi's avatar Rainer Koirikivi Committed by Tim Graham
Browse files

Fixed #20934 -- Avoided NoReverseMatch in ModelAdmin.changelist_view

The view tried to display links to a ModelAdmin's change_view, which
resulted in NoReverseMatches if get_urls was overridden to remove the
corresponding url.
parent 6af05e7a
Loading
Loading
Loading
Loading
+27 −15
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE,
    ORDER_VAR, PAGE_VAR, SEARCH_VAR)
from django.contrib.admin.templatetags.admin_static import static
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import NoReverseMatch
from django.db import models
from django.utils import formats
from django.utils.html import escapejs, format_html
@@ -216,9 +217,16 @@ def items_for_result(cl, result, form):
        row_class = mark_safe(' class="%s"' % ' '.join(row_classes))
        # If list_display_links not defined, add the link tag to the first field
        if (first and not cl.list_display_links) or field_name in cl.list_display_links:
            table_tag = {True:'th', False:'td'}[first]
            table_tag = 'th' if first else 'td'
            first = False

            # Display link to the result's change_view if the url exists, else
            # display just the result's representation.
            try:
                url = cl.url_for_result(result)
            except NoReverseMatch:
                link_or_text = result_repr
            else:
                url = add_preserved_filters({'preserved_filters': cl.preserved_filters, 'opts': cl.opts}, url)
                # Convert the pk to something that can be used in Javascript.
                # Problem cases are long ints (23L) and non-ASCII strings.
@@ -228,13 +236,17 @@ def items_for_result(cl, result, form):
                    attr = pk
                value = result.serializable_value(attr)
                result_id = escapejs(value)
            yield format_html('<{0}{1}><a href="{2}"{3}>{4}</a></{5}>',
                              table_tag,
                              row_class,
                link_or_text = format_html(
                    '<a href="{0}"{1}>{2}</a>',
                    url,
                    format_html(' onclick="opener.dismissRelatedLookupPopup(window, &#39;{0}&#39;); return false;"', result_id)
                        if cl.is_popup else '',
                              result_repr,
                    result_repr)

            yield format_html('<{0}{1}>{2}</{3}>',
                              table_tag,
                              row_class,
                              link_or_text,
                              table_tag)
        else:
            # By default the fields come from ModelAdmin.list_editable, but if we pull
+13 −0
Original line number Diff line number Diff line
@@ -630,6 +630,19 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
        with self.assertRaises(AttributeError):
            self.client.get('/test_admin/%s/admin_views/simple/' % self.urlbit)

    def test_changelist_with_no_change_url(self):
        """
        ModelAdmin.changelist_view shouldn't result in a NoReverseMatch if url
        for change_view is removed from get_urls

        Regression test for #20934
        """
        UnchangeableObject.objects.create()
        response = self.client.get('/test_admin/admin/admin_views/unchangeableobject/')
        self.assertEqual(response.status_code, 200)
        # Check the format of the shown object -- shouldn't contain a change link
        self.assertContains(response, '<th class="field-__str__">UnchangeableObject object</th>', html=True)


@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class AdminViewFormUrlTest(TestCase):