I am upgrading some code from wagtail 3.0 to wagtail 4.0. My code has one problem query in it that I can not figure out how to fix.
In the old code, the query looks like this:
PageRevision.objects.filter(approved_go_live_at__isnull=False, page__live=False)
With PageRevision being deprecated, I updated it to the following
Revision.page_revisions.filter(approved_go_live_at__isnull=False, page__live=False)
This resulted in an error, caused by a type mismatch in sql:
ProgrammingError: operator does not exist: character varying = integer
LINE 1: ...core_page" ON ("wagtailcore_revision"."object_id" = "wagtail...
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
After reexamining the docs I changed it to:
Revision.page_revisions.filter(approved_go_live_at__isnull=False, content_object__live=False)
This just got a different error:
FieldError: Field 'content_object' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.
Now I am confused, because content_object
is a field directly on Revision, so it shouldn't be a 'reverse` relation.
Looking at Page
, it seems like it does have a GenericRelation
, (with related_query_name=page
) pointing back to Revision. But that's what I tried to use the first time and got a sql type mismatch.
The documentation talks about type casting, but I don't see how to get django to type cast in the JOIN clause that it generates.
Final Question:
How can I query for Revision
s, filtering by a field on the related Page?
If you're using PostgreSQL, this is caused by a 12-year-old Django issue https://code.djangoproject.com/ticket/16055 that will be fixed in Django 5.0 (yet to be released at the time of writing).
A possible workaround:
from django.contrib.contenttypes.models import ContentType
from wagtail.models import Page, Revision
base_page_ct = ContentType.objects.get_for_model(Page)
not_live_ids = Page.objects.not_live().values_list('id', flat=True)
Revision.page_revisions.filter(base_content_type=base_page_ct, object_id__in=not_live_ids)
How can I query for relations, filtering by a field on the related Page?
I assume you mean "query for revisions"?
Using a similar trick as above, you can filter the page first, use values_list
to get the IDs, then filter the revisions by the base Page content type and the object IDs.
Since QuerySets are lazy, the first query to get the page IDs won't be evaluated directly and instead will be used as a subquery to revision query.