Expose URL resolver match for RoutablePageMixin (#11953)

Django provides an `HttpRequest.resolver_match` attribute [0] that
allows downstream code to inspect a request object to see how its URL
was resolved to a view.

Wagtail's RoutablePageMixin does its own sub-URL routing to call
different view functions on a page object, but the resolver result isn't
similarly made available.

This commit sets a new `routable_resolver_match` attribute on the
request object, akin to Django's `resolver_match`, that stores this
sub-URL routing information for downstream use.

Documentation has been updated appropriately (along with a couple of
other minor broken things in the RoutablePageMixin docs).

[0] https://docs.djangoproject.com/en/5.0/ref/request-response/#django.http.HttpRequest.resolver_match
pull/11965/head
Andy Chosak 2024-05-14 11:30:02 -04:00 zatwierdzone przez Matt Westcott
rodzic 37e367b7ed
commit a81cabce05
6 zmienionych plików z 37 dodań i 10 usunięć

Wyświetl plik

@ -20,6 +20,7 @@ Changelog
* Allow manually specifying credentials for CloudFront frontend cache backend (Jake Howard)
* Automatically register permissions for models registered with a `ModelViewSet` (Sage Abdullah)
* Implement universal listings UI for report views (Sage Abdullah)
* Make `routable_resolver_match` attribute available on RoutablePageMixin responses (Andy Chosak)
* Fix: Make `WAGTAILIMAGES_CHOOSER_PAGE_SIZE` setting functional again (Rohit Sharma)
* Fix: Enable `richtext` template tag to convert lazy translation values (Benjamin Bach)
* Fix: Ensure permission labels on group permissions page are translated where available (Matt Westcott)

Wyświetl plik

@ -137,10 +137,10 @@ def next_event(self, request):
'year/2015/'
```
This method only returns the part of the URL within the page. To get the full URL, you must append it to the values of either the {attr}`~wagtail.models.Page.url` or the {attr}`~wagtail.models.Page.full_url` attribute on your page:
This method only returns the part of the URL within the page. To get the full URL, you must append it to the values of either the {meth}`~wagtail.models.Page.get_url` method or the {attr}`~wagtail.models.Page.full_url` attribute on your page:
```python
>>> event_page.url + event_page.reverse_subpage('events_for_year', args=(2015, ))
>>> event_page.get_url() + event_page.reverse_subpage('events_for_year', args=(2015, ))
'/events/year/2015/'
>>> event_page.full_url + event_page.reverse_subpage('events_for_year', args=(2015, ))
@ -178,6 +178,15 @@ class EventPage(RoutablePageMixin, Page):
.. automodule:: wagtail.contrib.routable_page.models
.. autoclass:: RoutablePageMixin
.. automethod:: route
This method overrides the default :meth:`Page.route() <wagtail.models.Page.route>`
method to route requests to the appropriate view method.
It sets ``routable_resolver_match`` on the request object to make sub-URL routing
information available downstream in the same way that Django sets
:attr:`request.resolver_match <django.http.HttpRequest.resolver_match>`.
.. automethod:: render
.. automethod:: get_subpage_urls
@ -193,12 +202,11 @@ class EventPage(RoutablePageMixin, Page):
.. automethod:: reverse_subpage
```
Example:
Example:
.. code-block:: python
```python
url = page.url + page.reverse_subpage('events_for_year', kwargs={'year': '2014'})
url = page.url + page.reverse_subpage('events_for_year', kwargs={'year': '2014'})
```
(routablepageurl_template_tag)=

Wyświetl plik

@ -34,6 +34,7 @@ This feature was implemented by Albina Starykova, with support from the Wagtail
* Allow manually specifying credentials for CloudFront frontend cache backend (Jake Howard)
* Automatically register permissions for models registered with a `ModelViewSet` (Sage Abdullah)
* Implement universal listings UI for report views (Sage Abdullah)
* Make `routable_resolver_match` attribute available on RoutablePageMixin responses (Andy Chosak)
### Bug fixes

Wyświetl plik

@ -137,12 +137,12 @@ class RoutablePageMixin:
"""
This method takes a URL path and finds the view to call.
"""
view, args, kwargs = self.get_resolver().resolve(path)
resolver_match = self.get_resolver().resolve(path)
# Bind the method
view = view.__get__(self, type(self))
resolver_match.func = resolver_match.func.__get__(self, type(self))
return view, args, kwargs
return resolver_match
def route(self, request, path_components):
"""
@ -154,7 +154,9 @@ class RoutablePageMixin:
if path_components:
path += "/".join(path_components) + "/"
view, args, kwargs = self.resolve_subpage(path)
resolver_match = self.resolve_subpage(path)
request.routable_resolver_match = resolver_match
view, args, kwargs = resolver_match
return RouteResult(self, args=(view, args, kwargs))
except Http404:
pass

Wyświetl plik

@ -134,6 +134,9 @@ class TestRoutablePage(TestCase):
(context["page"], context["self"], context.get("foo")),
(self.routable_page, self.routable_page, None),
)
self.assertEqual(
context["request"].routable_resolver_match.url_name, "index_route"
)
def test_get_render_method_route_view(self):
with self.assertTemplateUsed("routablepagetests/routable_page_test.html"):
@ -157,6 +160,14 @@ class TestRoutablePage(TestCase):
(self.routable_page, 1, "fighters"),
)
def test_get_render_method_route_view_with_arg(self):
response = self.client.get(
self.routable_page.url + "render-method-with-arg/foo/"
)
resolver_match = response.context_data["request"].routable_resolver_match
self.assertEqual(resolver_match.url_name, "render_method_test_with_arg")
self.assertEqual(resolver_match.kwargs, {"slug": "foo"})
def test_get_routable_page_with_overridden_index_route(self):
page = self.home_page.add_child(
instance=RoutablePageWithOverriddenIndexRouteTest(

Wyświetl plik

@ -62,6 +62,10 @@ class RoutablePageTest(RoutablePage):
template="routablepagetests/routable_page_test_alternate.html",
)
@route(r"^render-method-with-arg/(?P<slug>.+)/$")
def render_method_test_with_arg(self, request, slug):
return self.render(request)
def get_route_paths(self):
return [
"/",