0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-11-29 09:33:54 +01:00

Take MRO into account when constructing RoutablePageMixin's list of routes

This ensures that routes can be overridden in subclasses, while still respecting the definition order within a class definition.
This commit is contained in:
Matt Westcott 2017-03-31 19:30:53 +01:00 committed by Karl Hobley
parent 44a1c28481
commit 913607c939
3 changed files with 25 additions and 8 deletions

View File

@ -49,15 +49,23 @@ class RoutablePageMixin(object):
@classmethod
def get_subpage_urls(cls):
routes = []
for attr in dir(cls):
val = getattr(cls, attr, None)
if hasattr(val, '_routablepage_routes'):
routes.extend(val._routablepage_routes)
return tuple([
route[0]
for route in reversed(sorted(routes, key=lambda route: route[1]))
])
# Loop over this class's defined routes, in method resolution order.
# Routes defined in the immediate class take precedence, followed by
# immediate superclass and so on
for klass in cls.__mro__:
routes_for_class = []
for val in klass.__dict__.values():
if hasattr(val, '_routablepage_routes'):
routes_for_class.extend(val._routablepage_routes)
# sort routes by _creation_counter so that ones earlier in the class definition
# take precedence
routes_for_class.sort(key=lambda route: route[1])
routes.extend(route[0] for route in routes_for_class)
return tuple(routes)
@classmethod
def get_resolver(cls):

View File

@ -110,6 +110,11 @@ class TestRoutablePage(TestCase):
self.assertContains(response, "ARCHIVE BY YEAR: 2014")
def test_earlier_view_takes_precedence(self):
response = self.client.get(self.routable_page.url + 'archive/year/1984/')
self.assertContains(response, "we were always at war with eastasia")
def test_get_archive_by_author_view(self):
response = self.client.get(self.routable_page.url + 'archive/author/joe-bloggs/')

View File

@ -10,6 +10,10 @@ def routable_page_external_view(request, arg="ARG NOT SET"):
class RoutablePageTest(RoutablePage):
@route(r'^archive/year/1984/$')
def archive_for_1984(self, request):
# check that routes are tested in order (and thus this takes precedence over archive_by_year)
return HttpResponse("we were always at war with eastasia")
@route(r'^archive/year/(\d+)/$')
def archive_by_year(self, request, year):