However, it is possible to implement your own task types. Instances of your custom task can then be created in the Workflow tasks section of the Wagtail Admin.
All custom tasks must be models inheriting from `wagtailcore.Task`.
If you need to customize the behavior of the built-in `GroupApprovalTask`, create a custom task which inherits from `AbstractGroupApprovalTask` and add your customizations there.
See below for more details on how to customize behavior.
In this set of examples, we'll set up a task that can be approved by only one specific user.
Subclassed Tasks follow the same approach as Pages: they are concrete models, with the specific subclass instance accessible by calling `Task.specific()`.
You can now add any custom fields. To make these editable in the admin, add the names of the fields into the `admin_form_fields` attribute:
For example:
```python
# <project>/models.py
from django.conf import settings
from django.db import models
from wagtail.models import Task
class UserApprovalTask(Task):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=False)
Any fields that shouldn't be edited after task creation - for example, anything that would fundamentally change the meaning of the task in any history logs - can be added to `admin_form_readonly_on_edit_fields`. For example:
```python
# <project>/models.py
from django.conf import settings
from django.db import models
from wagtail.models import Task
class UserApprovalTask(Task):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=False)
Wagtail will choose a default form widget to use based on the field type. But you can override the form widget using the `admin_form_widgets` attribute:
```python
# <project>/models.py
from django.conf import settings
from django.db import models
from wagtail.models import Task
from .widgets import CustomUserChooserWidget
class UserApprovalTask(Task):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=False)
This returns `True` if the object should be locked and uneditable by the user. It is used by `GroupApprovalTask` to lock the object to any users not in the approval group.
This returns a list of `(action_name, action_verbose_name, action_requires_additional_data_from_modal)` tuples, corresponding to the actions available for the task in the edit view menu.
`action_requires_additional_data_from_modal` should be a boolean, returning `True` if choosing the action should open a modal for additional data input - for example, entering a comment.
Returns a form to be used for additional data input for the given action modal. By default, returns `TaskStateCommentForm`, with a single comment field. The form data returned in `form.cleaned_data` must be fully serializable as JSON.
`Task.get_template_for_action(action)`:
Returns the name of a custom template to be used in rendering the data entry modal for that action.
This performs the actions specified in `Task.get_actions(obj, user)`: it is passed an action name, for example, `approve`, and the relevant task state. By default, it calls `approve` and `reject` methods on the task state when the corresponding action names are passed through. Any additional data entered in a modal (see `get_form_for_action` and `get_actions`) is supplied as kwargs.
This returns a QuerySet of `TaskStates` (or subclasses) that the given user can moderate - this is currently used to select objects to display on the user's dashboard.
`register_signal_handlers()` should then be run on loading the app: for example, by adding it to the `ready()` method in your `AppConfig`.
```python
# <project>/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myappname'
label = 'myapplabel'
verbose_name = 'My verbose app name'
def ready(self):
from .signal_handlers import register_signal_handlers
register_signal_handlers()
```
```{note}
In Django versions before 3.2 your `AppConfig` subclass needs to be set as `default_app_config` in `<project>/__init__.py`.
See the [relevant section in the Django docs](https://docs.djangoproject.com/en/3.1/ref/applications/#for-application-authors) for the version you are using.