Browse Source

Allow ChooserViewSet to be filtered by specified URL parameters

Matt Westcott 1 year ago
parent
commit
7b64f08e74

+ 1 - 0
docs/reference/viewsets.md

@@ -128,6 +128,7 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
    .. autoattribute:: edit_item_text
    .. autoattribute:: per_page
    .. autoattribute:: preserve_url_parameters
+   .. autoattribute:: url_filter_parameters
    .. autoattribute:: choose_view_class
    .. autoattribute:: choose_results_view_class
    .. autoattribute:: chosen_view_class

+ 16 - 1
wagtail/admin/tests/viewsets/test_chooser_viewset.py

@@ -12,7 +12,9 @@ class TestChooserViewSetWithFilteredObjects(WagtailTestUtils, TestCase):
 
         Advert.objects.create(text="Head On, apply directly to the forehead")
 
-        advert2 = Advert.objects.create(text="We like the subs")
+        advert2 = Advert.objects.create(
+            url="https://quiznos.com", text="We like the subs"
+        )
         advert2.tags.add("animated")
 
     def test_get(self):
@@ -20,3 +22,16 @@ class TestChooserViewSetWithFilteredObjects(WagtailTestUtils, TestCase):
         response_html = json.loads(response.content)["html"]
         self.assertIn("We like the subs", response_html)
         self.assertNotIn("Head On, apply directly to the forehead", response_html)
+
+    def test_filter_by_url(self):
+        response = self.client.get(
+            "/admin/animated_advert_chooser/", {"url": "https://quiznos.com"}
+        )
+        response_html = json.loads(response.content)["html"]
+        self.assertIn("We like the subs", response_html)
+
+        response = self.client.get(
+            "/admin/animated_advert_chooser/", {"url": "https://subway.com"}
+        )
+        response_html = json.loads(response.content)["html"]
+        self.assertNotIn("We like the subs", response_html)

+ 10 - 0
wagtail/admin/views/generic/chooser.py

@@ -130,6 +130,7 @@ class BaseChooseView(
     template_name = "wagtailadmin/generic/chooser/chooser.html"
     results_template_name = "wagtailadmin/generic/chooser/results.html"
     construct_queryset_hook_name = None
+    url_filter_parameters = []
 
     def get_object_list(self):
         return self.model_class.objects.all()
@@ -174,6 +175,15 @@ class BaseChooseView(
         return FilterForm(self.request.GET)
 
     def filter_object_list(self, objects):
+        filters = {}
+        for filter in self.url_filter_parameters:
+            try:
+                filters[filter] = self.request.GET[filter]
+            except KeyError:
+                pass
+        if filters:
+            objects = objects.filter(**filters)
+
         if self.construct_queryset_hook_name:
             # allow hooks to modify the queryset
             for hook in hooks.get_hooks(self.construct_queryset_hook_name):

+ 5 - 0
wagtail/admin/viewsets/chooser.py

@@ -35,6 +35,10 @@ class ChooserViewSet(ViewSet):
     #: form submissions within the chooser modal workflow.
     preserve_url_parameters = ["multiple"]
 
+    #: A list of URL query parameters that, if present in the url, should be applied as filters to the queryset.
+    #: (These should also be listed in `preserve_url_parameters`.)
+    url_filter_parameters = []
+
     #: The view class to use for the overall chooser modal; must be a subclass of ``wagtail.admin.views.generic.chooser.ChooseView``.
     choose_view_class = chooser_views.ChooseView
 
@@ -93,6 +97,7 @@ class ChooserViewSet(ViewSet):
                 "model": self.model,
                 "permission_policy": self.permission_policy,
                 "preserve_url_parameters": self.preserve_url_parameters,
+                "url_filter_parameters": self.url_filter_parameters,
                 "create_action_label": self.create_action_label,
                 "create_action_clicked_label": self.create_action_clicked_label,
                 "creation_form_class": self.creation_form_class,

+ 2 - 0
wagtail/test/testapp/views.py

@@ -255,6 +255,8 @@ class ToyViewSetGroup(ModelViewSetGroup):
 class AnimatedAdvertChooserViewSet(ChooserViewSet):
     model = Advert
     register_widget = False  # don't make this the registered widget for Advert
+    url_filter_parameters = ["url"]
+    preserve_url_parameters = ["multiple", "url"]
 
     def get_object_list(self):
         return Advert.objects.filter(tags__name="animated")