# Imports
from django.conf import settings
from django.db import models
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from superdjango.shortcuts import get_user_name
from ..audit.utils import is_audit_model
# Exports
__all__ = (
"ArchivedModel",
)
# Constants
AUTH_USER_MODEL = settings.AUTH_USER_MODEL
# Models
[docs]class ArchivedModel(models.Model):
"""Supports records that may be archived.
**Fields**
- ``archived_by``
- ``archived_dt``
- ``is_archived``
**Proper Name**
The ``archived_by_name`` property is also provided which attempts to return the full name of the user.
**Methods**
- ``mark_archived()``
- ``mark_unarchived()``
"""
cached_archived_by_name = models.CharField(
_("archived by"),
blank=True,
help_text=_("The name of the person that archived the record."),
max_length=256,
null=True
)
archived_by = models.ForeignKey(
AUTH_USER_MODEL,
blank=True,
help_text=_("The user that archived the record."),
null=True,
on_delete=models.SET_NULL,
related_name="%(app_label)s_%(class)s_archived_records",
verbose_name=_("archived by")
)
archived_dt = models.DateTimeField(
_("archived date/time"),
blank=True,
help_text=_("Date and time the record was archived."),
null=True
)
is_archived = models.BooleanField(
_("is archived"),
default=False,
help_text=_("Indicates the record is archived.")
)
class Meta:
abstract = True
@property
def archived_by_name(self):
"""Get the name of the user that archived the record.
:rtype: str | None
"""
return self.cached_archived_by_name
[docs] def mark_archived(self, user, audit=True, commit=True):
"""Mark the record as archived.
:param user: The user marking the record as archived.
:type user: AUTH_USER_MODEL
:param audit: Call the ``audit()`` method if this is also an audit model.
:type audit: bool
:param commit: Whether to save immediately.
:type commit: bool
.. note::
Mark archived changes the record only if ``archived_dt`` is ``None``. This prevents updating the user
or date/time if ``mark_archived()`` is called more than once.
"""
if self.archived_dt is None:
self.cached_archived_by_name = get_user_name(user)
self.archived_dt = now()
self.is_archived = True
self.archived_by = user
self._also_update(True)
if audit and is_audit_model(self):
# noinspection PyUnresolvedReferences
self.audit(user, commit=False)
if commit:
self.save()
[docs] def mark_unarchived(self, user, audit=True, commit=True):
"""Mark the record as un-archived.
:param user: The user marking the record as un-archived.
:type user: AUTH_USER_MODEL
:param audit: Call the ``audit()`` method if this is also an audit model.
:type audit: bool
:param commit: Whether to save immediately.
:type commit: bool
"""
self.cached_archived_by_name = None
self.archived_dt = None
self.is_archived = False
self.archived_by = None
self._also_update(False)
if audit and is_audit_model(self):
# noinspection PyUnresolvedReferences
self.audit(user, commit=False)
if commit:
self.save()
def _also_update(self, archived):
"""A callback that may be used to update other fields on the record.
:param archived: Indicates whether ``mark_archived()` or ``mark_unarchived()`` is making the call.
:type archived: bool
.. warning::
Set fields here as needed, but do *not* call ``save()``.
"""
pass