wagtail / wagtail

A Django content management system focused on flexibility and user experience

Home Page:https://wagtail.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Image admin pages fail with 404 when using tag filters and pagination

dkirkham opened this issue · comments

commented

Issue Summary

When using the image admin pages (/admin/images/), a 404 error arises when applying a tag filter from page > 1 and there are not enough images with that tag to occupy the requested page number.

Steps to Reproduce

  1. Start a new project using the Quick Install instructions.
  2. Login to admin and go to the images admin page, there will be no images.
  3. Upload 11 images. Tag six with one tag, the remaining five with another tag.
  4. Return to the images page and select 10 entries per page. All but one image will be visible.
  5. Click "Next" to go to the second image admin page. Only one image will be visible.
  6. Click on one of the tags.
  7. Observe the 404 page.

Other image numbers and tagging will result in the same behaviour, if the number of images with the selected tag is less than the number of images needed to populate the image admin pages up to the current image admin page.

I consider this a bug since selecting a tag shouldn't cause a 404.

Possible alternative behaviours: When a tag is clicked/selected, and there are not enough images to populate the requested page number, that page number should be ignored and either reset to page 1 or set to the maximum available page number that can be populated with images.

  • I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: (yes)

I initially noticed this on a Wagtail 2.15 deployment. I then checked Wagtail 6.0.1 as described above and the problem was still present. It's probably affecting every version in between.

Apologies if the bug has already been reported – I did search the issues list with a number of keyword searches, but the relevant terms are pretty common, so I had to search manually.

Technical details

  • Python version: 3.8, 3.10.
  • Django version: 4.0, 5.0
  • Wagtail version: 2.15, 6.0.1
  • Browser version: Firefox 122

Working on this

Anyone can contribute to this. View our contributing guidelines, add a comment to the issue once you’re ready to start.

We reproduced the problem and showed me a 404 error. I want to address this issue. I need some help to get started.
See demo video

I checked this locally and was able to reproduce, however the query params for clicking the tags also includes the page number you are currently on. Not sure if this is intended behaviour or not but removing that param makes it work as intended
image

Django version : 4.1
Wagtail version : 5.2
Python version : 3.12.1

I've loooked into this and what I found is that in Djangos MultipleObjectMixin paginate_queryset() method. The queryset that gets passed to that method is the filtrered by tag queryset, which is usually less than the entries per page set by us. Also, because we still have the page query parameter in the url set at the second page, what happens is that in this block of code

try:
    page = paginator.page(page_number)
    return (paginator, page, page.object_list, page.has_other_pages())
except InvalidPage as e:
     raise Http404(
         _("Invalid page (%(page_number)s): %(message)s")
         % {"page_number": page_number, "message": str(e)}
      )

located here, the paginator tries to request the second page, which usually does not exist if we are filtered by tag and causes a 404.

I have two ideas in mind:

  1. override paginate_queryset in image index view to be as follows:
    When where we are in any page other than the first and we need to filter by tag, filter the pagination result. The problem here we can't filter a sliced queryset, so we need a workaround.

  2. When filtering by tag return to the first page instantly, not really a good solution I believe.

I've loooked into this and what I found is that in Djangos MultipleObjectMixin paginate_queryset() method. The queryset that gets passed to that method is the filtrered by tag queryset, which is usually less than the entries per page set by us. Also, because we still have the page query parameter in the url set at the second page, what happens is that in this block of code

try:
    page = paginator.page(page_number)
    return (paginator, page, page.object_list, page.has_other_pages())
except InvalidPage as e:
     raise Http404(
         _("Invalid page (%(page_number)s): %(message)s")
         % {"page_number": page_number, "message": str(e)}
      )

located here, the paginator tries to request the second page, which usually does not exist if we are filtered by tag and causes a 404.

I have two ideas in mind:

  1. override paginate_queryset in image index view to be as follows:
    When where we are in any page other than the first and we need to filter by tag, filter the pagination result. The problem here we can't filter a sliced queryset, so we need a workaround.
  2. When filtering by tag return to the first page instantly, not really a good solution I believe.

I am pretty sure Solution 2 is the intended way to handle tag filtering in any sort of collection management. It does not make sense to select a different tag three pages in and miss out on said tags in previous pages. Although rather than return to first page, just that the page query param should not be present when clicking on the tag filter.

Yeah, I agree with @A-Amen's point. That's how the new filters in 6.0 work for pages and snippets too.

Just a heads up to anyone who's interested in working on this: in the next release, we are planning to reimplement the filters using django-filter to align with the new filters UI for pages and snippets. The work is planned to be done in this release (sometime in the next month or so).

It's unlikely we're going to accept a quick fix (e.g. by removing the page parameter from the tag filter links), as that will be undone when the filters are reimplemented anyway. So, unless you'd like to have a go at reimplementing the filters using django-filter, I'd suggest spending your time on a different issue 😄

I think if this needs a proper fix, it would be more than just replacing the page parameter(eg other parameters, contextual vars etc). But since you are going to be using django-filters sometime soon, it is best to await that release.