Recording Which User Changed a Model
There are four documented ways to attach users to a tracked change:
1. Use the
HistoryRequestMiddleware. The middleware sets the
User instance that made the request as the
history_user on the history
simple_history.admin.SimpleHistoryAdmin. Under the hood,
SimpleHistoryAdmin actually sets the
_history_user on the object to
attach the user to the tracked change by overriding the save_model method.
3. Assign a user to the
_history_user attribute of the object as described
in the _history_user section.
4. Track the user using an explicit
history_user_id, which is described in
Manually Track User Model. This method is particularly useful when using multiple
databases (where your user model lives in a separate database to your historical model),
or when using a user that doesn’t live within the Django app (i.e. a user model retrieved
from an API).
_history_user to Record Which User Changed a Model
To denote which user changed a model, assign a
_history_user attribute on
For example if you have a
changed_by field on your model that records which
user last changed the model, you could create a
from django.db import models from simple_history.models import HistoricalRecords class Poll(models.Model): question = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') changed_by = models.ForeignKey('auth.User') history = HistoricalRecords() @property def _history_user(self): return self.changed_by @_history_user.setter def _history_user(self, value): self.changed_by = value
Admin integration requires that you use a
_history_user.setter attribute with
_history_user property (see Admin Integration).
Another option for identifying the change user is by providing a function via
If provided it will be called every time that the
history_user needs to be
identified with the following key word arguments:
instance: The current instance being modified
request: If using the middleware the current request object will be provided if they are authenticated.
This is very helpful when using
from django.db import models from simple_history.models import HistoricalRecords class Poll(models.Model): question = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') changed_by = models.ForeignKey('auth.User') def get_poll_user(instance, **kwargs): return instance.changed_by register(Poll, get_user=get_poll_user)
Manually Track User Model
django-simple-history tracks the
history_user (the user who changed the
model) using a django foreign key, there are instances where we might want to track this
user but cannot use a Django foreign key.
Note: If you want to track a custom user model that is still accessible through a Django foreign key, refer to Change User Model.
The two most common cases where this feature will be helpful are:
You are working on a Django app with multiple databases, and your history table is in a separate database from the user table.
The user model that you want to use for
history_userdoes not live within the Django app, but is only accessible elsewhere (i.e. through an API call).
There are three parameters to
register that facilitate
the ability to manually track a
An instance of field (i.e.
UUIDField(default=uuid.uuid4, null=True)that will uniquely identify your user object. This is generally the field type of the primary key on your user object.
optional. A callable that takes the historical instance of the model and returns the
history_userobject. The default getter is shown below:
def _history_user_getter(historical_instance): if historical_instance.history_user_id is None: return None User = get_user_model() try: return User.objects.get(pk=historical_instance.history_user_id) except User.DoesNotExist: return None
optional. A callable that takes the historical instance and the user instance, and sets
history_user_idon the historical instance. The default setter is shown below:
def _history_user_setter(historical_instance, user): if user is not None: historical_instance.history_user_id = user.pk
Change User Model
If you need to use a different user model then
pass in the required model to
user_model. Doing this requires
get_user is provided as detailed above.
from django.db import models from simple_history.models import HistoricalRecords class PollUser(models.Model): user_id = models.ForeignKey('auth.User') # Only PollUsers should be modifying a Poll class Poll(models.Model): question = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') changed_by = models.ForeignKey(PollUser) history = HistoricalRecords(user_model=PollUser) @property def _history_user(self): return self.changed_by @_history_user.setter def _history_user(self, value): self.changed_by = value