Source code for djem.forms.bases
import warnings
from django import forms
[docs]class UserSavable:
"""
A mixin for a Django ``ModelForm`` that adds support for models using the
:class:`~djem.models.Auditable` model mixin. It handles providing a user
instance to the model's ``save()`` method when the form's own ``save()``
method is called, as is required by :class:`~djem.models.Auditable`.
This mixin *assumes* the presence of a ``self.user`` attribute that the
``save()`` method can use. It is designed for use by forms that already
accept and store a known user, e.g. as a constructor argument.
For a form that provides the same customisation of the ``save()`` method
and includes ``user`` as a constructor argument, see :class:`AuditableForm`.
"""
def save(self, commit=True):
# Call super.save() with commit=False so .save() can be called on the
# instance with the required user argument
instance = super().save(commit=False)
if commit:
instance.save(self.user)
self.save_m2m()
del self.save_m2m # pretend commit=False was never used
return instance
[docs]class AuditableForm(UserSavable, forms.ModelForm):
"""
A Django ``ModelForm`` that is customised to support models using the
:class:`~djem.models.Auditable` model mixin. It handles providing a user
instance to the model's ``save()`` method when the form's own ``save()``
method is called, as is required by :class:`~djem.models.Auditable`. It
also adds a ``user`` keyword argument to the constructor so the ``save()``
method has a known user to work with. The ``user`` argument is required if
the field is bound, otherwise it is optional. The given user is stored in
the :attr:`~AuditableForm.user` instance attribute. Subclasses may choose
to use the known user for their own purposes.
For a mixin that provides the same customisation of the ``save()`` method
without the extra constructor argument (e.g. for use by forms that already
accept and store a known user), see :class:`UserSavable`.
"""
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
# User is required for bound forms
if self.is_bound and not user:
raise TypeError('Bound {0} instances require a "user" argument.'.format(self.__class__.__name__))
# Set self.user regardless of whether or not the form is bound. Child
# forms may well require the user when the form is unbound as well.
self.user = user
# Backwards compat.
# TODO: Remove in 1.0
class CommonInfoForm(AuditableForm):
def __init__(self, *args, **kwargs):
warnings.warn('Use of CommonInfoForm is deprecated, use AuditableForm instead.', DeprecationWarning)
super().__init__(*args, **kwargs)