mirror of
https://github.com/wagtail/wagtail.git
synced 2024-12-01 11:41:20 +01:00
Avoid querying with GenericRelations
to prevent crash on Postgres
Upstream issue: https://code.djangoproject.com/ticket/16055
This commit is contained in:
parent
b151180cc8
commit
c008fdfb39
@ -21,6 +21,7 @@ from wagtail.models import (
|
||||
WorkflowPage,
|
||||
WorkflowState,
|
||||
WorkflowTask,
|
||||
get_default_page_content_type,
|
||||
)
|
||||
from wagtail.signals import page_published
|
||||
from wagtail.test.testapp.models import SimplePage, SimpleTask
|
||||
@ -1168,8 +1169,8 @@ class TestApproveRejectWorkflow(TestCase, WagtailTestUtils):
|
||||
|
||||
# Check that the workflow was approved
|
||||
|
||||
workflow_state = WorkflowState.objects.get(
|
||||
page=self.page, requested_by=self.submitter
|
||||
workflow_state = WorkflowState.objects.for_instance(self.page).get(
|
||||
requested_by=self.submitter
|
||||
)
|
||||
|
||||
self.assertEqual(workflow_state.status, workflow_state.STATUS_APPROVED)
|
||||
@ -1303,8 +1304,8 @@ class TestApproveRejectWorkflow(TestCase, WagtailTestUtils):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Check that the workflow state was marked as cancelled
|
||||
workflow_state = WorkflowState.objects.get(
|
||||
page=self.page, requested_by=self.submitter
|
||||
workflow_state = WorkflowState.objects.for_instance(self.page).get(
|
||||
requested_by=self.submitter
|
||||
)
|
||||
self.assertEqual(workflow_state.status, WorkflowState.STATUS_CANCELLED)
|
||||
|
||||
@ -1322,8 +1323,8 @@ class TestApproveRejectWorkflow(TestCase, WagtailTestUtils):
|
||||
|
||||
# Check that the workflow was marked as needing changes
|
||||
|
||||
workflow_state = WorkflowState.objects.get(
|
||||
page=self.page, requested_by=self.submitter
|
||||
workflow_state = WorkflowState.objects.for_instance(self.page).get(
|
||||
requested_by=self.submitter
|
||||
)
|
||||
|
||||
self.assertEqual(workflow_state.status, workflow_state.STATUS_NEEDS_CHANGES)
|
||||
@ -1434,8 +1435,8 @@ class TestApproveRejectWorkflow(TestCase, WagtailTestUtils):
|
||||
|
||||
# Check that the workflow was approved
|
||||
|
||||
workflow_state = WorkflowState.objects.get(
|
||||
page=self.page, requested_by=self.submitter
|
||||
workflow_state = WorkflowState.objects.for_instance(self.page).get(
|
||||
requested_by=self.submitter
|
||||
)
|
||||
|
||||
self.assertEqual(workflow_state.status, workflow_state.STATUS_APPROVED)
|
||||
@ -1902,7 +1903,9 @@ class TestDisableViews(TestCase, WagtailTestUtils):
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.workflow.refresh_from_db()
|
||||
self.assertIs(self.workflow.active, False)
|
||||
states = WorkflowState.objects.filter(page=self.page, workflow=self.workflow)
|
||||
states = WorkflowState.objects.for_instance(self.page).filter(
|
||||
workflow=self.workflow
|
||||
)
|
||||
self.assertEqual(
|
||||
states.filter(status=WorkflowState.STATUS_IN_PROGRESS).count(), 0
|
||||
)
|
||||
@ -1964,7 +1967,9 @@ class TestDisableViews(TestCase, WagtailTestUtils):
|
||||
self.task_1.refresh_from_db()
|
||||
self.assertIs(self.task_1.active, False)
|
||||
states = TaskState.objects.filter(
|
||||
workflow_state__page=self.page, task=self.task_1.task_ptr
|
||||
workflow_state__base_content_type_id=get_default_page_content_type().id,
|
||||
workflow_state__object_id=str(self.page.id),
|
||||
task=self.task_1.task_ptr,
|
||||
)
|
||||
self.assertEqual(states.filter(status=TaskState.STATUS_IN_PROGRESS).count(), 0)
|
||||
self.assertEqual(states.filter(status=TaskState.STATUS_CANCELLED).count(), 1)
|
||||
|
@ -5,7 +5,8 @@ from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.db import connection
|
||||
from django.db.models import Max, Q
|
||||
from django.db.models import CharField, IntegerField, Max, OuterRef, Q, Subquery
|
||||
from django.db.models.functions import Cast
|
||||
from django.forms import Media
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.template.loader import render_to_string
|
||||
@ -118,10 +119,23 @@ class UserPagesInWorkflowModerationPanel(Component):
|
||||
request = parent_context["request"]
|
||||
context = super().get_context_data(parent_context)
|
||||
if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
|
||||
# Need to cast the page ids to string because Postgres doesn't support
|
||||
# implicit type casts when querying on GenericRelations. We also need
|
||||
# to cast the object_id to integer when querying the pages for the same reason.
|
||||
# https://code.djangoproject.com/ticket/16055
|
||||
# Once the issue is resolved, the subquery can be removed and the
|
||||
# filter can be changed to:
|
||||
# Q(page__owner=request.user) | Q(requested_by=request.user)
|
||||
owned_by_user = Subquery(
|
||||
Page.objects.filter(
|
||||
owner=request.user,
|
||||
id=Cast(OuterRef("object_id"), output_field=IntegerField()),
|
||||
).values_list(Cast("id", output_field=CharField()), flat=True)
|
||||
)
|
||||
# Find in progress workflow states which are either requested by the user or on pages owned by the user
|
||||
context["workflow_states"] = (
|
||||
WorkflowState.objects.active()
|
||||
.filter(Q(page__owner=request.user) | Q(requested_by=request.user))
|
||||
.filter(Q(object_id__in=owned_by_user) | Q(requested_by=request.user))
|
||||
.prefetch_related("content_object")
|
||||
.select_related(
|
||||
"current_task_state",
|
||||
|
@ -20,6 +20,7 @@ from wagtail.models import (
|
||||
TaskState,
|
||||
UserPagePermissionsProxy,
|
||||
WorkflowState,
|
||||
get_default_page_content_type,
|
||||
)
|
||||
|
||||
|
||||
@ -59,7 +60,7 @@ def workflow_history(request, page_id):
|
||||
if not user_perms.for_page(page).can_edit():
|
||||
raise PermissionDenied
|
||||
|
||||
workflow_states = WorkflowState.objects.filter(page=page).order_by("-created_at")
|
||||
workflow_states = WorkflowState.objects.for_instance(page).order_by("-created_at")
|
||||
|
||||
paginator = Paginator(workflow_states, per_page=20)
|
||||
workflow_states = paginator.get_page(request.GET.get("p"))
|
||||
@ -81,7 +82,14 @@ def workflow_history_detail(request, page_id, workflow_state_id):
|
||||
if not user_perms.for_page(page).can_edit():
|
||||
raise PermissionDenied
|
||||
|
||||
workflow_state = get_object_or_404(WorkflowState, page=page, id=workflow_state_id)
|
||||
# Change to page=page once this issue is resolved:
|
||||
# https://code.djangoproject.com/ticket/16055
|
||||
workflow_state = get_object_or_404(
|
||||
WorkflowState,
|
||||
base_content_type_id=get_default_page_content_type().id,
|
||||
object_id=str(page.id),
|
||||
id=workflow_state_id,
|
||||
)
|
||||
|
||||
# Get QuerySet of all revisions that have existed during this workflow state
|
||||
# It's possible that the page is edited while the workflow is running, so some
|
||||
|
@ -2,6 +2,8 @@ import datetime
|
||||
|
||||
import django_filters
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models import CharField
|
||||
from django.db.models.functions import Cast
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from wagtail.admin.filters import (
|
||||
@ -16,6 +18,7 @@ from wagtail.models import (
|
||||
UserPagePermissionsProxy,
|
||||
Workflow,
|
||||
WorkflowState,
|
||||
get_default_page_content_type,
|
||||
)
|
||||
|
||||
from .base import ReportView
|
||||
@ -137,7 +140,17 @@ class WorkflowView(ReportView):
|
||||
|
||||
def get_queryset(self):
|
||||
pages = UserPagePermissionsProxy(self.request.user).editable_pages()
|
||||
return WorkflowState.objects.filter(page__in=pages).order_by("-created_at")
|
||||
# Need to cast the page ids to string because Postgres doesn't support
|
||||
# implicit type casts when querying on GenericRelations
|
||||
# https://code.djangoproject.com/ticket/16055
|
||||
# Once the issue is resolved, we can change the query to
|
||||
# page__in=pages
|
||||
page_ids = pages.values_list(Cast("id", output_field=CharField()), flat=True)
|
||||
return (
|
||||
WorkflowState.objects.for_pages()
|
||||
.filter(object_id__in=page_ids)
|
||||
.order_by("-created_at")
|
||||
)
|
||||
|
||||
|
||||
class WorkflowTasksView(ReportView):
|
||||
@ -174,6 +187,13 @@ class WorkflowTasksView(ReportView):
|
||||
|
||||
def get_queryset(self):
|
||||
pages = UserPagePermissionsProxy(self.request.user).editable_pages()
|
||||
return TaskState.objects.filter(workflow_state__page__in=pages).order_by(
|
||||
"-started_at"
|
||||
)
|
||||
# Need to cast the page ids to string because Postgres doesn't support
|
||||
# implicit type casts when querying on GenericRelations
|
||||
# https://code.djangoproject.com/ticket/16055
|
||||
# Once the issue is resolved, we can change the query to
|
||||
# workflow_state__page_in=pages
|
||||
page_ids = pages.values_list(Cast("id", output_field=CharField()), flat=True)
|
||||
return TaskState.objects.filter(
|
||||
workflow_state__base_content_type_id=get_default_page_content_type().id,
|
||||
workflow_state__object_id__in=page_ids,
|
||||
).order_by("-started_at")
|
||||
|
Loading…
Reference in New Issue
Block a user