Ветвление рабочих процессов на основе значения указанного поля Page
У меня есть модель DailyReflectionPage
с полем reflection_date
, которое формирует основу для slug страницы, имеющего форму YYYY-MM-DD
. Вот выдержка из моей модели Page:
class DailyReflectionPage(Page):
"""
The Daily Reflection Model
"""
...
...
reflection_date = models.DateField("Reflection Date", max_length=254)
...
...
@cached_property
def date(self):
"""
Returns the Reflection's date as a string in %Y-%m-%d format
"""
fmt = "%Y-%m-%d"
date_as_string = (self.reflection_date).strftime(fmt)
return date_as_string
...
...
def full_clean(self, *args, **kwargs):
# first call the built-in cleanups (including default slug generation)
super(DailyReflectionPage, self).full_clean(*args, **kwargs)
# now make your additional modifications
if self.slug is not self.date:
self.slug = self.date
...
...
Эти ежедневные размышления пишутся разными авторами в рамках буклета, который публикуется в конце года и предназначен для использования в следующем году. Я бы хотел, чтобы рабочий процесс, например, ежедневные размышления с января по июнь рассматривались одной группой, а с июля по декабрь - другой, как показано на схеме ниже:
Как этого можно достичь?
Этого можно достичь, создав ОДИН новый тип рабочего процесса Task
, который имеет отношение к двум наборам пользователей Group
(например, a/b или before/after, вероятно, лучше оставить это общим в определении модели).
Этот новый Task
может быть создан как часть нового Workflow
в админке Wagtail, и каждая из групп, связанных с группой модератора 1 / 2.
Методы Wagtail на Task
позволяют возвращать варианты утверждения на основе модели Page
для любого созданного рабочего процесса, отсюда вы можете искать метод, который был бы на классе, и назначать группы оттуда.
Преимущества более общего подхода в том, что вы можете использовать его для любого разделения заданий модераторов в рамках будущих задач Workflow.
Обзор внедрения
- 1 - прочитайте Wagatail Docs о том, как добавить новый тип задачи и
Task
model reference, чтобы понять этот процесс. - 2 - Прочитайте полную реализацию в коде встроенного
GroupApprovalTask
. - 3 - В
GroupApprovalTask
вы можете увидеть, что методы с переопределениями все полагаются на проверкуself.groups
, но все они получаютpage
, переданные в качестве аргумента этим методам. - 4 - Создайте новую модель
Task
, расширяющую класс WagtailTask
и на этой модели создайте две моделиManyToManyField
, позволяющие связать два набора групп пользователей (примечание: не обязательно делать это в виде двух полей, можно поместить модель в середину, но приведенный ниже пример - это просто простейший способ добраться до гала). - 5 - На модели
DailyReflectionPage
создайте методget_approval_group_key
, который будет возвращать, возможно, простое булево или 'A' или 'B' на основе бизнес-требований, описанных вами выше (проверка даты модели и т.д.) - 6 - В вашем пользовательском
Task
создайте метод, который абстрагирует проверкуPage
для этого метода и возвращает группу пользователей Задачи. Возможно, вы захотите добавить некоторую обработку ошибок и значения по умолчанию. Например,get_approval_groups
.
- 7 - Добавьте пользовательский метод для каждого из методов 'start', 'user_can_access_editor',
page_locked_for_user
,user_can_lock
,user_can_unlock
,get_task_states_user_can_moderate
, который вызываетget_approval_group
со страницей и возвращает значения (см. кодGroupApprovalTask
для того, что они должны делать. ).
Примеры фрагментов кода
models.py
class DailyReflectionPage(Page):
"""
The Daily Reflection Model
"""
def get_approval_group_key(self):
# custom logic here that checks all the date stuff
if date_is_after_foo:
return 'A'
return 'B'
class SplitGroupApprovalTask(Task):
## note: this is the simplest approach, two fields of linked groups, you could further refine this approach as needed.
groups_a = models.ManyToManyField(
Group,
help_text="Pages at this step in a workflow will be moderated or approved by these groups of users",
related_name="split_task_group_a",
)
groups_b = models.ManyToManyField(
Group,
help_text="Pages at this step in a workflow will be moderated or approved by these groups of users",
related_name="split_task_group_b",
)
admin_form_fields = Task.admin_form_fields + ["groups_a", "groups_b"]
admin_form_widgets = {
"groups_a": forms.CheckboxSelectMultiple,
"groups_b": forms.CheckboxSelectMultiple,
}
def get_approval_groups(self, page):
"""This method gets used by all checks when determining what group to allow/assign this Task to"""
# recommend some checks here, what if `get_approval_group` is not on the Page?
approval_group = page.specific.get_approval_group_key()
if (approval_group == 'A'):
return self.group_a
return self.group_b
# each of the following methods will need to be implemented, all checking for the correct groups for the Page when called
# def start(self, ...etc)
# def user_can_access_editor(self, ...etc)
# def page_locked_for_user(self, ...etc)
# def user_can_lock(self, ...etc)
# def user_can_unlock(self, ...etc)
# def get_task_states_user_can_moderate(self, ...etc)
def get_actions(self, page, user):
# essentially a copy of this method on `GroupApprovalTask` but with the ability to have a dynamic 'group' returned.
approval_groups = self.get_approval_groups(page)
if approval_groups.filter(id__in=user.groups.all()).exists() or user.is_superuser:
return [
('reject', "Request changes", True),
('approve', "Approve", False),
('approve', "Approve with comment", True),
]
return super().get_actions(page, user)