2

I have a field in a model called profile_images, how do I restrict the images shown in the image chooser panel to the profile images collection?

I also want to do the same with an inline panel for the gallery collection.

This means I cannot use permissions as the user should have access to both collections.

Thanks for the help

James
  • 23
  • 3

1 Answers1

3

Wagtail has a feature called hooks that lets you modify some of the Wagtail internal logic, this is a very helpful feature that can enable you to do this.

There is a hook called construct_image_chooser_queryset. You will need to create a file wagtail_hooks.py in one of your app folders, this gets run by Wagtail when the app runs.

Once you have the hook running, you can inject custom filtering of the images results for the image chooser modal. This hook will run for various image listings throughout Wagtail so you will want to add some logic to ensure you are not filtering the images everywhere.

A potential approach would be to read the request, which is passed into the hook, to determine if the current request is for a page editing scenario. Once you know this, you can work out what page class is being used and then filter your images based on some class method on the page class.

When the request is made for the image chooser modal, you can read the HTTP_REFERRER and from that URL use Django's resolve to determine where it was called and what page is being edited.

Example

  • Using the hook described above, we read the HTTP_REFERRER
  • Use urlparse and resolve to return a Django match object
  • Read the match data to confirm we are editing a page
  • If editing a page, we query for that Page and use the specific_class property
  • Finally, we can get a collection id from the class to filter images
  • Note: how you get the collection id is 100% up to you, you could hard code it, make it a separate function or even make it a specific class method, just be careful to ensure that it will all work if that method is not available on ALL pages.
  • Test this across other image choosers to ensure nothing else breaks.
  • This will not 'hide' the collection drop-down on the image chooser modal, you may just need to do this with CSS or JS unfortunately.
wagtail_hooks.py
from django.urls import resolve
from urllib.parse import urlparse
from wagtail.core import hooks
from wagtail.core.models import Page


@hooks.register('construct_image_chooser_queryset')
def show_images_for_specific_collections_on_page_editing(images, request):

    # first - pull out the referrer for this current AJAX call
    http_referrer = request.META.get('HTTP_REFERER', None) or '/'

    # second - use django utils to find the matched view
    match = resolve(urlparse(http_referrer)[2])

    # if we are editing a page we can restrict the available images
    if (match.app_name is 'wagtailadmin_pages') and (match.url_name is 'edit'):
        page = Page.objects.get(pk=match.args[0])

        # important: wrap in a try/except as this may not be implemented on all pages
        image_collection_id = page.specific_class.get_image_collection()

        # return filtered images
        return images.filter(collection=image_collection_id)

    return images
models.py
from wagtail.core.models import Page


class BlogPage(Page):
    # ...

    @classmethod
    def get_image_collection(cls):
        # any logic here to determine what collection to filter by
        return 4

LB Ben Johnston
  • 4,751
  • 13
  • 29
  • 1
    Thanks. This worked well before Wagtail 2.10 but not anymore. Seems like you need to replace `match.args[0]` with `match.kwargs['page_id']`. – Benoît Vogel Apr 25 '21 at 02:14
  • when I filter the images I get the error that 'ImageQuerySet' object has no attribute 'id' `File "/opt/django/apps/project/venv/lib/python3.10/site-packages/wagtail/images/views/chooser.py", line 123, in get_context_data reverse(chosen_url_name, args=(image.id,)) AttributeError: 'ImageQuerySet' object has no attribute 'id'` – N. Ahlers Jul 10 '23 at 09:28