Documentation - Improve code highlighting & formatting for Python docstrings in core models

pull/12477/head
Srishti-j18 2024-10-21 20:10:00 +05:30 zatwierdzone przez LB (Ben Johnston)
rodzic 37d9d7eb06
commit 652de3fcb3
6 zmienionych plików z 168 dodań i 92 usunięć

Wyświetl plik

@ -15,6 +15,8 @@ Changelog
* Docs: Add the `wagtail start` command to the management commands reference page (Damilola Oladele)
* Docs: Refine the project template page sections and document common issues encountered when creating custom templates (Damilola Oladele)
* Docs: Refine page titles to better align with the documentation style guide (Srishti Jaiswal)
* Docs: Recommend a larger `DATA_UPLOAD_MAX_NUMBER_FIELDS` when integrating Wagtail into Django (Matt Westcott)
* Docs: Improve code highlighting and formatting for Python docstrings in core models (Srishti Jaiswal)
* Maintenance: Close open files when reading within utils/setup.py (Ataf Fazledin Ahamed)

Wyświetl plik

@ -143,7 +143,7 @@ This document contains reference information for the model classes inside the `w
A UUID that is shared between translations of a page. These are randomly generated
when a new page is created and copied when a translation of a page is made.
A translation_key value can only be used on one page in each locale.
A ``translation_key`` value can only be used on one page in each locale.
```
### Methods and properties
@ -361,7 +361,7 @@ See also [django-treebeard](https://django-treebeard.readthedocs.io/en/latest/in
.. attribute:: exclude_fields_in_copy
An array of field names that will not be included when a Page is copied.
Useful when you have relations that do not use `ClusterableModel` or should not be copied.
Useful when you have relations that do not use ``ClusterableModel`` or should not be copied.
.. code-block:: python
@ -931,7 +931,7 @@ Workflows represent sequences of tasks that must be approved for an action to be
(boolean)
Whether or not the workflow is active: active workflows can be added to pages and snippets, and started. Inactive workflows cannot.
Whether or not the workflow is active. Active workflows can be added to pages and snippets, and started. Inactive workflows cannot.
```
### Methods and properties
@ -986,7 +986,7 @@ Workflow states represent the status of a started workflow on an object.
(foreign key to ``Workflow``)
The workflow whose state the ``WorkflowState`` represents
The workflow whose state the ``WorkflowState`` represents.
.. attribute:: status

Wyświetl plik

@ -33,6 +33,7 @@ depth: 1
* Refine the [](project_templates_reference) page sections and document common issues encountered when creating custom templates (Damilola Oladele)
* Refine page titles to better align with the documentation style guide (Srishti Jaiswal)
* Recommend a larger `DATA_UPLOAD_MAX_NUMBER_FIELDS` when [integrating Wagtail into Django](../getting_started/integrating_into_django.md) (Matt Westcott)
* Improve code highlighting and formatting for Python docstrings in core models (Srishti Jaiswal)
### Maintenance

Wyświetl plik

@ -1,8 +1,8 @@
"""
wagtail.models is split into submodules for maintainability. All definitions intended as
``wagtail.models`` is split into submodules for maintainability. All definitions intended as
public should be imported here (with 'noqa: F401' comments as required) and outside code should
continue to import them from wagtail.models (e.g. `from wagtail.models import Site`, not
`from wagtail.models.sites import Site`.)
continue to import them from wagtail.models (e.g. ``from wagtail.models import Site``, not
``from wagtail.models.sites import Site``.)
Submodules should take care to keep the direction of dependencies consistent; where possible they
should implement low-level generic functionality which is then imported by higher-level models such
@ -208,7 +208,7 @@ class BasePageManager(models.Manager):
def first_common_ancestor_of(self, pages, include_self=False, strict=False):
"""
This is similar to `PageQuerySet.first_common_ancestor` but works
This is similar to ``PageQuerySet.first_common_ancestor`` but works
for a list of pages instead of a queryset.
"""
if not pages:
@ -243,12 +243,12 @@ class BasePageManager(models.Manager):
If given a QuerySet, this method will evaluate it. Only use this method
when you are ready to consume the queryset, e.g. after pagination has
been applied. This is typically done in the view's `get_context_data`
using `context["object_list"]`.
been applied. This is typically done in the view's ``get_context_data``
using ``context["object_list"]``.
This method does not return a new queryset, but modifies the existing one,
to ensure any references to the queryset in the view's context are updated
(e.g. when using `context_object_name`).
(e.g. when using ``context_object_name``).
"""
parent_page_paths = {
Page._get_parent_path_from_path(page.path) for page in pages
@ -328,7 +328,7 @@ class RevisionMixin(models.Model):
Subclasses should define a
:class:`~django.contrib.contenttypes.fields.GenericRelation` to
:class:`~wagtail.models.Revision` and override this property to return
that ``GenericRelation``. This allows subclasses to customise the
that ``GenericRelation``. This allows subclasses to customize the
``related_query_name`` of the ``GenericRelation`` and add custom logic
(e.g. to always use the specific instance in ``Page``).
"""
@ -1070,11 +1070,15 @@ class WorkflowMixin:
@property
def has_workflow(self):
"""Returns True if the object has an active workflow assigned, otherwise False."""
"""
Returns ```True``` if the object has an active workflow assigned, otherwise ```False```.
"""
return self.get_workflow() is not None
def get_workflow(self):
"""Returns the active workflow assigned to the object."""
"""
Returns the active workflow assigned to the object.
"""
return self.get_default_workflow()
@property
@ -1094,12 +1098,14 @@ class WorkflowMixin:
@property
def workflow_in_progress(self):
"""Returns True if a workflow is in progress on the current object, otherwise False."""
"""
Returns ```True``` if a workflow is in progress on the current object, otherwise ```False```.
"""
if not getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
return False
# `_current_workflow_states` may be populated by `prefetch_workflow_states`
# on querysets as a performance optimisation
# on querysets as a performance optimization
if hasattr(self, "_current_workflow_states"):
for state in self._current_workflow_states:
if state.status == WorkflowState.STATUS_IN_PROGRESS:
@ -1112,12 +1118,14 @@ class WorkflowMixin:
@property
def current_workflow_state(self):
"""Returns the in progress or needs changes workflow state on this object, if it exists."""
"""
Returns the in progress or needs changes workflow state on this object, if it exists.
"""
if not getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
return None
# `_current_workflow_states` may be populated by `prefetch_workflow_states`
# on querysets as a performance optimisation
# on querysets as a performance optimization
if hasattr(self, "_current_workflow_states"):
try:
return self._current_workflow_states[0]
@ -1132,7 +1140,9 @@ class WorkflowMixin:
@property
def current_workflow_task_state(self):
"""Returns (specific class of) the current task state of the workflow on this object, if it exists."""
"""
Returns (specific class of) the current task state of the workflow on this object, if it exists.
"""
current_workflow_state = self.current_workflow_state
if (
current_workflow_state
@ -1143,7 +1153,9 @@ class WorkflowMixin:
@property
def current_workflow_task(self):
"""Returns (specific class of) the current task in progress on this object, if it exists."""
"""
Returns (specific class of) the current task in progress on this object, if it exists.
"""
current_workflow_task_state = self.current_workflow_task_state
if current_workflow_task_state:
return current_workflow_task_state.task.specific
@ -1386,7 +1398,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
"""
Find the page route for the given HTTP request object, and URL path. The route
result (`page`, `args`, and `kwargs`) will be cached via
`request._wagtail_route_for_request`.
``request._wagtail_route_for_request``.
"""
if not hasattr(request, "_wagtail_route_for_request"):
try:
@ -1412,7 +1424,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
def find_for_request(request: HttpRequest, path: str) -> Page | None:
"""
Find the page for the given HTTP request object, and URL path. The full
page route will be cached via `request._wagtail_route_for_request`
page route will be cached via ``request._wagtail_route_for_request``.
"""
result = Page.route_for_request(request, path)
if result is not None:
@ -1574,11 +1586,12 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
# ensure that changes are only committed when we have updated all descendant URL paths, to preserve consistency
def save(self, clean=True, user=None, log_action=False, **kwargs):
"""
Overrides default method behaviour to make additional updates unique to pages,
Overrides default method behavior to make additional updates unique to pages,
such as updating the ``url_path`` value of descendant page to reflect changes
to this page's slug.
New pages should generally be saved via the `add_child() <https://django-treebeard.readthedocs.io/en/latest/mp_tree.html#treebeard.mp_tree.MP_Node.add_child>`_ or `add_sibling() <https://django-treebeard.readthedocs.io/en/latest/mp_tree.html#treebeard.mp_tree.MP_Node.add_sibling>`_
New pages should generally be saved via the `add_child() <https://django-treebeard.readthedocs.io/en/latest/mp_tree.html#treebeard.mp_tree.MP_Node.add_child>`_
or `add_sibling() <https://django-treebeard.readthedocs.io/en/latest/mp_tree.html#treebeard.mp_tree.MP_Node.add_sibling>`_
method of an existing page, which will correctly set the ``path`` and ``depth``
fields on the new page before saving it.
@ -1745,7 +1758,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@property
def page_type_display_name(self):
"""
A human-readable version of this page's type
A human-readable version of this page's type.
"""
if not self.specific_class or self.is_root():
return ""
@ -2117,7 +2130,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
"""
Determine the URL for this page and return it as a tuple of
``(site_id, site_root_url, page_url_relative_to_site_root)``.
Return None if the page is not routable.
Return ``None`` if the page is not routable.
This is used internally by the ``full_url``, ``url``, ``relative_url``
and ``get_site`` properties and methods; pages with custom URL routing
@ -2187,7 +2200,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
return (site_id, root_url, page_path)
def get_full_url(self, request=None):
"""Return the full URL (including protocol / domain) to this page, or None if it is not routable"""
"""
Return the full URL (including protocol / domain) to this page, or ``None`` if it is not routable.
"""
url_parts = self.get_url_parts(request=request)
if url_parts is None or url_parts[1] is None and url_parts[2] is None:
@ -2207,7 +2222,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
this is the local URL (starting with '/') if we're only running a single site
(i.e. we know that whatever the current page is being served from, this link will be on the
same domain), and the full URL (with domain) if not.
Return None if the page is not routable.
Return ``None`` if the page is not routable.
Accepts an optional but recommended ``request`` keyword argument that, if provided, will
be used to cache site-level URL information (thereby avoiding repeated database / cache
@ -2246,7 +2261,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
"""
Return the 'most appropriate' URL for this page taking into account the site we're currently on;
a local URL if the site matches, or a fully qualified one otherwise.
Return None if the page is not routable.
Return ``None`` if the page is not routable.
Accepts an optional but recommended ``request`` keyword argument that, if provided, will
be used to cache site-level URL information (thereby avoiding repeated database / cache
@ -2287,8 +2302,8 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@classmethod
def clean_subpage_models(cls):
"""
Returns the list of subpage types, normalised as model classes.
Throws ValueError if any entry in subpage_types cannot be recognised as a model name,
Returns the list of subpage types, normalized as model classes.
Throws ValueError if any entry in subpage_types cannot be recognized as a model name,
or LookupError if a model does not exist (or is not a Page subclass).
"""
if cls._clean_subpage_models is None:
@ -2311,8 +2326,8 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@classmethod
def clean_parent_page_models(cls):
"""
Returns the list of parent page types, normalised as model classes.
Throws ValueError if any entry in parent_page_types cannot be recognised as a model name,
Returns the list of parent page types, normalized as model classes.
Throws ValueError if any entry in parent_page_types cannot be recognized as a model name,
or LookupError if a model does not exist (or is not a Page subclass).
"""
@ -2337,7 +2352,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
def allowed_parent_page_models(cls):
"""
Returns the list of page types that this page type can be a subpage of,
as a list of model classes
as a list of model classes.
"""
return [
parent_model
@ -2349,7 +2364,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
def allowed_subpage_models(cls):
"""
Returns the list of page types that this page type can have as subpages,
as a list of model classes
as a list of model classes.
"""
return [
subpage_model
@ -2361,7 +2376,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
def creatable_subpage_models(cls):
"""
Returns the list of page types that may be created under this page type,
as a list of model classes
as a list of model classes.
"""
return [
page_model
@ -2438,8 +2453,10 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@property
def approved_schedule(self):
# `_approved_schedule` may be populated by `annotate_approved_schedule` on `PageQuerySet` as a
# performance optimisation
"""
``_approved_schedule`` may be populated by ``annotate_approved_schedule`` on ``PageQuerySet`` as a
performance optimization.
"""
if hasattr(self, "_approved_schedule"):
return self._approved_schedule
@ -2478,7 +2495,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
"""
Copies a given page
:param log_action: flag for logging the action. Pass None to skip logging. Can be passed an action string. Defaults to 'wagtail.copy'
:param log_action: flag for logging the action. Pass None to skip logging. Can be passed an action string. Defaults to ``'wagtail.copy'``.
"""
return CopyPageAction(
self,
@ -2539,7 +2556,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
def permissions_for_user(self, user):
"""
Return a PagePermissionsTester object defining what actions the user can perform on this page
Return a PagePermissionsTester object defining what actions the user can perform on this page.
"""
# Allow specific classes to override this method, but only cast to the
# specific instance if it's not already specific and if the method has
@ -2695,9 +2712,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
"""
Serve a response indicating that the user has been denied access to view this page,
and must supply a password.
form = a Django form object containing the password input
``form`` = a Django form object containing the password input
(and zero or more hidden fields that also need to be output on the template)
action_url = URL that this form should be POSTed to
``action_url`` = URL that this form should be POSTed to
"""
password_required_template = self.password_required_template
@ -2815,7 +2832,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
@property
def has_workflow(self):
"""Returns True if the page or an ancestor has an active workflow assigned, otherwise False"""
"""
Returns ``True`` if the page or an ancestor has an active workflow assigned, otherwise ``False``.
"""
if not getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
return False
return (
@ -2826,7 +2845,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
)
def get_workflow(self):
"""Returns the active workflow assigned to the page or its nearest ancestor"""
"""
Returns the active workflow assigned to the page or its nearest ancestor.
"""
if not getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
return None
@ -2902,7 +2923,7 @@ class RevisionsManager(models.Manager.from_queryset(RevisionQuerySet)):
of the previous revision, based on the revision_fk_name field. Useful
to avoid N+1 queries when generating comparison links between revisions.
The logic is similar to Revision.get_previous().pk.
The logic is similar to ``Revision.get_previous().pk``.
"""
fk = revision_fk_name
return Subquery(
@ -3465,7 +3486,7 @@ class PageViewRestriction(BaseViewRestriction):
def delete(self, user=None, **kwargs):
"""
Custom delete handler to aid in logging
Custom delete handler to aid in logging.
:param user: the user removing the view restriction
"""
specific_instance = self.page.specific
@ -3506,9 +3527,9 @@ class WorkflowPage(models.Model):
def get_pages(self):
"""
Returns a queryset of pages that are affected by this WorkflowPage link.
Returns a queryset of pages that are affected by this ``WorkflowPage`` link.
This includes all descendants of the page excluding any that have other WorkflowPages.
This includes all descendants of the page excluding any that have other ``WorkflowPage``(s).
"""
descendant_pages = Page.objects.descendant_of(self.page, inclusive=True)
descendant_workflow_pages = WorkflowPage.objects.filter(
@ -3614,12 +3635,16 @@ class Task(SpecificMixin, models.Model):
@property
def workflows(self):
"""Returns all ``Workflow`` instances that use this task"""
"""
Returns all ``Workflow`` instances that use this task.
"""
return Workflow.objects.filter(workflow_tasks__task=self)
@property
def active_workflows(self):
"""Return a ``QuerySet``` of active workflows that this task is part of"""
"""
Return a ``QuerySet``` of active workflows that this task is part of.
"""
return Workflow.objects.active().filter(workflow_tasks__task=self)
@classmethod
@ -3638,7 +3663,9 @@ class Task(SpecificMixin, models.Model):
return self.task_state_class or TaskState
def start(self, workflow_state, user=None):
"""Start this task on the provided workflow state by creating an instance of TaskState"""
"""
Start this task on the provided workflow state by creating an instance of TaskState.
"""
task_state = self.get_task_state_class()(workflow_state=workflow_state)
task_state.status = TaskState.STATUS_IN_PROGRESS
task_state.revision = workflow_state.content_object.get_latest_revision()
@ -3653,39 +3680,50 @@ class Task(SpecificMixin, models.Model):
@transaction.atomic
def on_action(self, task_state, user, action_name, **kwargs):
"""Performs an action on a task state determined by the ``action_name`` string passed"""
"""
Performs an action on a task state determined by the ``action_name`` string passed.
"""
if action_name == "approve":
task_state.approve(user=user, **kwargs)
elif action_name == "reject":
task_state.reject(user=user, **kwargs)
def user_can_access_editor(self, obj, user):
"""Returns True if a user who would not normally be able to access the editor for the object should be able to if the object is currently on this task.
Note that returning False does not remove permissions from users who would otherwise have them."""
"""
Returns ``True`` if a user who would not normally be able to access the editor for the
object should be able to if the object is currently on this task.
Note that returning ``False`` does not remove permissions from users who would otherwise have them.
"""
return False
def locked_for_user(self, obj, user):
"""
Returns True if the object should be locked to a given user's edits.
Returns ``True`` if the object should be locked to a given user's edits.
This can be used to prevent editing by non-reviewers.
"""
return False
def user_can_lock(self, obj, user):
"""Returns True if a user who would not normally be able to lock the object should be able to if the object is currently on this task.
Note that returning False does not remove permissions from users who would otherwise have them."""
"""
Returns ``True`` if a user who would not normally be able to lock the object should be able to
if the object is currently on this task.
Note that returning ``False`` does not remove permissions from users who would otherwise have them.
"""
return False
def user_can_unlock(self, obj, user):
"""Returns True if a user who would not normally be able to unlock the object should be able to if the object is currently on this task.
Note that returning False does not remove permissions from users who would otherwise have them."""
"""
Returns ``True`` if a user who would not normally be able to unlock the object should be able to
if the object is currently on this task.
Note that returning ``False`` does not remove permissions from users who would otherwise have them.
"""
return False
def get_actions(self, obj, user):
"""
Get the list of action strings (name, verbose_name, whether the action requires additional data - see
``get_form_for_action``) for actions the current user can perform for this task on the given object.
These strings should be the same as those able to be passed to ``on_action``
These strings should be the same as those able to be passed to ``on_action``.
"""
return []
@ -3701,12 +3739,16 @@ class Task(SpecificMixin, models.Model):
@classmethod
def get_description(cls):
"""Returns the task description."""
"""
Returns the task description.
"""
return ""
@transaction.atomic
def deactivate(self, user=None):
"""Set ``active`` to False and cancel all in progress task states linked to this task"""
"""
Set ``active`` to False and cancel all in progress task states linked to this task.
"""
self.active = False
self.save()
in_progress_states = TaskState.objects.filter(
@ -3741,14 +3783,18 @@ class AbstractWorkflow(ClusterableModel):
@property
def tasks(self):
"""Returns all ``Task`` instances linked to this workflow"""
"""
Returns all ``Task`` instances linked to this workflow.
"""
return Task.objects.filter(workflow_tasks__workflow=self).order_by(
"workflow_tasks__sort_order"
)
@transaction.atomic
def start(self, obj, user):
"""Initiates a workflow by creating an instance of ``WorkflowState``"""
"""
Initiates a workflow by creating an instance of ``WorkflowState``.
"""
state = WorkflowState(
content_type=obj.get_content_type(),
base_content_type=obj.get_base_content_type(),
@ -3789,7 +3835,9 @@ class AbstractWorkflow(ClusterableModel):
@transaction.atomic
def deactivate(self, user=None):
"""Sets the workflow as inactive, and cancels all in progress instances of ``WorkflowState`` linked to this workflow"""
"""
Sets the workflow as inactive, and cancels all in progress instances of ``WorkflowState`` linked to this workflow.
"""
self.active = False
in_progress_states = WorkflowState.objects.filter(
workflow=self, status=WorkflowState.STATUS_IN_PROGRESS
@ -3915,7 +3963,7 @@ class GroupApprovalTask(AbstractGroupApprovalTask):
class WorkflowStateQuerySet(models.QuerySet):
def active(self):
"""
Filters to only STATUS_IN_PROGRESS and STATUS_NEEDS_CHANGES WorkflowStates
Filters to only ``STATUS_IN_PROGRESS`` and ``STATUS_NEEDS_CHANGES`` WorkflowStates.
"""
return self.filter(
Q(status=WorkflowState.STATUS_IN_PROGRESS)
@ -3924,7 +3972,7 @@ class WorkflowStateQuerySet(models.QuerySet):
def for_instance(self, instance):
"""
Filters to only WorkflowStates for the given instance
Filters to only WorkflowStates for the given instance.
"""
try:
# Use RevisionMixin.get_base_content_type() if available
@ -4106,8 +4154,10 @@ class WorkflowState(models.Model):
)
def update(self, user=None, next_task=None):
"""Checks the status of the current task, and progresses (or ends) the workflow if appropriate. If the workflow progresses,
next_task will be used to start a specific task next if provided."""
"""
Checks the status of the current task, and progresses (or ends) the workflow if appropriate.
If the workflow progresses, next_task will be used to start a specific task next if provided.
"""
if self.status != self.STATUS_IN_PROGRESS:
# Updating a completed or cancelled workflow should have no effect
return
@ -4156,7 +4206,9 @@ class WorkflowState(models.Model):
return successful_task_states
def get_next_task(self):
"""Returns the next active task, which has not been either approved or skipped"""
"""
Returns the next active task, which has not been either approved or skipped.
"""
return (
Task.objects.filter(workflow_tasks__workflow=self.workflow, active=True)
@ -4202,7 +4254,9 @@ class WorkflowState(models.Model):
@transaction.atomic
def finish(self, user=None):
"""Finishes a successful in progress workflow, marking it as approved and performing the ``on_finish`` action"""
"""
Finishes a successful in progress workflow, marking it as approved and performing the ``on_finish`` action.
"""
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = self.STATUS_APPROVED
@ -4211,7 +4265,9 @@ class WorkflowState(models.Model):
workflow_approved.send(sender=self.__class__, instance=self, user=user)
def copy_approved_task_states_to_revision(self, revision):
"""This creates copies of previously approved task states with revision set to a different revision."""
"""
Creates copies of previously approved task states with revision set to a different revision.
"""
approved_states = TaskState.objects.filter(
workflow_state=self, status=TaskState.STATUS_APPROVED
)
@ -4219,7 +4275,9 @@ class WorkflowState(models.Model):
state.copy(update_attrs={"revision": revision})
def revisions(self):
"""Returns all revisions associated with task states linked to the current workflow state"""
"""
Returns all revisions associated with task states linked to the current workflow state.
"""
return Revision.objects.filter(
base_content_type_id=self.base_content_type_id,
object_id=self.object_id,
@ -4227,7 +4285,9 @@ class WorkflowState(models.Model):
).defer("content")
def _get_applicable_task_states(self):
"""Returns the set of task states whose status applies to the current revision"""
"""
Returns the set of task states whose status applies to the current revision.
"""
task_states = TaskState.objects.filter(workflow_state_id=self.id)
# If WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT=True, this is only task states created on the current revision
@ -4245,8 +4305,8 @@ class WorkflowState(models.Model):
"""
Returns a list of Task objects that are linked with this workflow state's
workflow. The status of that task in this workflow state is annotated in the
`.status` field. And a displayable version of that status is annotated in the
`.status_display` field.
``.status`` field. And a displayable version of that status is annotated in the
``.status_display`` field.
This is different to querying TaskState as it also returns tasks that haven't
been started yet (so won't have a TaskState).
@ -4308,7 +4368,9 @@ class WorkflowState(models.Model):
@property
def is_at_final_task(self):
"""Returns the next active task, which has not been either approved or skipped"""
"""
Returns the next active task, which has not been either approved or skipped.
"""
last_task = (
Task.objects.filter(workflow_tasks__workflow=self.workflow, active=True)
@ -4458,7 +4520,9 @@ class TaskState(SpecificMixin, models.Model):
@transaction.atomic
def approve(self, user=None, update=True, comment=""):
"""Approve the task state and update the workflow state"""
"""
Approve the task state and update the workflow state.
"""
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = self.STATUS_APPROVED
@ -4477,7 +4541,9 @@ class TaskState(SpecificMixin, models.Model):
@transaction.atomic
def reject(self, user=None, update=True, comment=""):
"""Reject the task state and update the workflow state"""
"""
Reject the task state and update the workflow state.
"""
if self.status != self.STATUS_IN_PROGRESS:
raise PermissionDenied
self.status = self.STATUS_REJECTED
@ -4497,7 +4563,9 @@ class TaskState(SpecificMixin, models.Model):
@cached_property
def task_type_started_at(self):
"""Finds the first chronological started_at for successive TaskStates - ie started_at if the task had not been restarted"""
"""
Finds the first chronological started_at for successive TaskStates - ie started_at if the task had not been restarted.
"""
task_states = (
TaskState.objects.filter(workflow_state=self.workflow_state)
.order_by("-started_at")
@ -4513,8 +4581,11 @@ class TaskState(SpecificMixin, models.Model):
@transaction.atomic
def cancel(self, user=None, resume=False, comment=""):
"""Cancel the task state and update the workflow state. If ``resume`` is set to True, then upon update the workflow state
is passed the current task as ``next_task``, causing it to start a new task state on the current task if possible"""
"""
Cancel the task state and update the workflow state.
If ``resume`` is set to True, then upon update the workflow state is passed the current task as ``next_task``,
causing it to start a new task state on the current task if possible.
"""
self.status = self.STATUS_CANCELLED
self.finished_at = timezone.now()
self.comment = comment
@ -4530,8 +4601,10 @@ class TaskState(SpecificMixin, models.Model):
return self
def copy(self, update_attrs=None, exclude_fields=None):
"""Copy this task state, excluding the attributes in the ``exclude_fields`` list and updating any attributes to values
specified in the ``update_attrs`` dictionary of ``attribute``: ``new value`` pairs"""
"""
Copy this task state, excluding the attributes in the ``exclude_fields`` list and updating any attributes
to values specified in the ``update_attrs`` dictionary of ``attribute``: ``new value`` pairs.
"""
exclude_fields = (
self.default_exclude_fields_in_copy
+ self.exclude_fields_in_copy
@ -4777,7 +4850,7 @@ class Comment(ClusterableModel):
def has_valid_contentpath(self, page):
"""
Return True if this comment's contentpath corresponds to a valid field or
StreamField block on the given page object
StreamField block on the given page object.
"""
field_name, *remainder = self.contentpath.split(".")
try:

Wyświetl plik

@ -56,7 +56,7 @@ class Locale(models.Model):
@classmethod
def get_default(cls):
"""
Returns the default Locale based on the site's LANGUAGE_CODE setting
Returns the default Locale based on the site's ``LANGUAGE_CODE`` setting.
"""
return cls.objects.get_for_language(settings.LANGUAGE_CODE)
@ -309,7 +309,7 @@ class TranslatableMixin(models.Model):
"""
Finds the translation in the specified locale.
If there is no translation in that locale, this returns None.
If there is no translation in that locale, this returns ``None``.
"""
try:
return self.get_translation(locale)

Wyświetl plik

@ -206,15 +206,15 @@ class Site(models.Model):
def get_site_root_paths():
"""
Return a list of `SiteRootPath` instances, most specific path
first - used to translate url_paths into actual URLs with hostnames
first - used to translate url_paths into actual URLs with hostnames.
Each root path is an instance of the `SiteRootPath` named tuple,
and have the following attributes:
- `site_id` - The ID of the Site record
- `root_path` - The internal URL path of the site's home page (for example '/home/')
- `root_url` - The scheme/domain name of the site (for example 'https://www.example.com/')
- `language_code` - The language code of the site (for example 'en')
- ``site_id`` - The ID of the Site record
- ``root_path`` - The internal URL path of the site's home page (for example '/home/')
- ``root_url`` - The scheme/domain name of the site (for example 'https://www.example.com/')
- ``language_code`` - The language code of the site (for example 'en')
"""
result = cache.get(
SITE_ROOT_PATHS_CACHE_KEY, version=SITE_ROOT_PATHS_CACHE_VERSION