From 895196695e6c58b35033267148336a1c1e391e98 Mon Sep 17 00:00:00 2001 From: James Murty Date: Mon, 10 Oct 2016 14:06:55 +1100 Subject: [PATCH] Make publishing filters work with generic Fluent models, re #32 Make the `PublishingPublishedFilter` and `PublishingStatusFilter` publishing status admin filters compatible with models that do not provide the standard ICEKit publishing features (and DB fields) from `PublishingModel`. This change is necessary to make these filters usable on parent admin pages that can include non-`PublishingModel` class, in particular the Fluent Pages default parent page admin listing /admin/fluent_pages/page/ This change is a hack and requires iterating over the actual instances of all models so it will be slow in cases where we cannot rely on `PublishingModel` fields being present, but works around the problem for now of filtering by two different publishing notions in the one polymorphic parent admin page. --- icekit/publishing/admin.py | 84 +++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/icekit/publishing/admin.py b/icekit/publishing/admin.py index 08bb366e..c8e308ef 100644 --- a/icekit/publishing/admin.py +++ b/icekit/publishing/admin.py @@ -56,8 +56,30 @@ def queryset(self, request, queryset): except TypeError: return queryset - isnull = not value - return queryset.filter(publishing_linked__isnull=isnull) + show_published = bool(value) + + # If admin is for a `PublishingModel` subclass use simple query... + if issubclass(queryset.model, PublishingModel): + return queryset.filter( + publishing_linked__isnull=not show_published) + + # ...if admin is not for a `PublishingModel` subclass we must iterate + # over child model instances to keep compatibility with Fluent page + # admin and models not derived from `PublishingModel`. + pks_to_exclude = [] + for item in queryset.get_real_instances(): + if show_published: + if item.status == UrlNode.PUBLISHED: + continue # Published according to Fluent Pages' UrlNode + elif getattr(item, 'has_been_published', False): + continue # Published according to ICEKit Publishing + else: + if item.status == UrlNode.DRAFT \ + and not getattr(item, 'has_been_published', False): + # Unpublished according to both Fluent and ICEKit + continue + pks_to_exclude.append(item.pk) + return queryset.exclude(pk__in=pks_to_exclude) class PublishingStatusFilter(SimpleListFilter): @@ -100,18 +122,52 @@ def lookups(self, request, model_admin): return lookups def queryset(self, request, queryset): - if self.value() == 'unpublished': - return queryset.filter(publishing_linked__isnull=True) - elif self.value() == 'published': - return queryset.filter(publishing_linked__isnull=False) - elif self.value() == 'out_of_date': - return queryset.filter( - publishing_modified_at__gt=F( - 'publishing_linked__publishing_modified_at')) - elif self.value() == 'up_to_date': - return queryset.filter( - publishing_modified_at__lte=F( - 'publishing_linked__publishing_modified_at')) + value = self.value() + if not value: + return queryset + # If admin is for a `PublishingModel` subclass use simple queries... + if issubclass(queryset.model, PublishingModel): + if value == 'unpublished': + return queryset.filter(publishing_linked__isnull=True) + elif value == 'published': + return queryset.filter(publishing_linked__isnull=False) + elif value == 'out_of_date': + return queryset.filter( + publishing_modified_at__gt=F( + 'publishing_linked__publishing_modified_at')) + elif value == 'up_to_date': + return queryset.filter( + publishing_modified_at__lte=F( + 'publishing_linked__publishing_modified_at')) + # ...if admin is not for a `PublishingModel` subclass we must iterate + # over child model instances to keep compatibility with Fluent page + # admin and models not derived from `PublishingModel`. + pks_to_exclude = [] + for item in queryset.get_real_instances(): + if value == 'unpublished': + if item.status == UrlNode.DRAFT \ + and not getattr(item, 'has_been_published', False): + # Unpublished according to both Fluent and ICEKit + continue + elif value == 'published': + if item.status == UrlNode.PUBLISHED: + continue # Published according to Fluent Pages' UrlNode + elif getattr(item, 'has_been_published', False): + continue # Published according to ICEKit Publishing + elif value == 'out_of_date': + if (getattr(item, 'publishing_linked', None) + and item.publishing_modified_at + > item.publishing_linked.publishing_modified_at + ): + continue # Published and outdated according to ICEKit + elif value == 'up_to_date': + if (getattr(item, 'publishing_linked', None) + and item.publishing_modified_at + <= item.publishing_linked.publishing_modified_at + ): + continue # Published and up-to-date according to ICEKit + pks_to_exclude.append(item.pk) + return queryset.exclude(pk__in=pks_to_exclude) class PublishingAdminForm(forms.ModelForm):