Skip to content

Commit 5ab0c97

Browse files
committed
Added history_user middleware
1 parent 7cec7da commit 5ab0c97

File tree

5 files changed

+45
-2
lines changed

5 files changed

+45
-2
lines changed

docs/usage.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ Django tutorial:
4646
Now all changes to ``Poll`` and ``Choice`` model instances will be tracked in
4747
the database.
4848

49+
The historical models can also track who made each change. To populate
50+
the history user automatically you can add middleware to your Django
51+
settings:
52+
53+
.. code-block:: python
54+
55+
MIDDLEWARE_CLASSES = [
56+
# ...
57+
'simple_history.middleware.HistoryRequestMiddleware',
58+
]
59+
60+
If you do not want to use the middleware, you can explicitly indicate
61+
the user making the change as indicated in the advanced usage
62+
documentation.
63+
4964
.. _admin_integration:
5065

5166
Integration with Django Admin

runtests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
'django.contrib.sessions.middleware.SessionMiddleware',
3838
'django.contrib.auth.middleware.AuthenticationMiddleware',
3939
'django.contrib.messages.middleware.MessageMiddleware',
40+
'simple_history.middleware.HistoryRequestMiddleware',
4041
],
4142
)
4243

simple_history/middleware.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from . models import HistoricalRecords
2+
3+
4+
class HistoryRequestMiddleware(object):
5+
"""Expose the request as a thread-friendly variable on the
6+
HistoricalRecords class.
7+
8+
"""
9+
10+
def process_request(self, request):
11+
HistoricalRecords.thread.request = request

simple_history/models.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import unicode_literals
22

3+
import threading
34
import copy
45
try:
56
from django.apps import apps # Django >= 1.7
@@ -53,6 +54,8 @@ def python_2_unicode_compatible(klass):
5354

5455

5556
class HistoricalRecords(object):
57+
thread = threading.local()
58+
5659
def __init__(self, verbose_name=None, bases=(models.Model,)):
5760
self.user_set_verbose_name = verbose_name
5861
try:
@@ -213,14 +216,27 @@ def post_delete(self, instance, **kwargs):
213216

214217
def create_historical_record(self, instance, type):
215218
history_date = getattr(instance, '_history_date', now())
216-
history_user = getattr(instance, '_history_user', None)
219+
history_user = self.get_history_user(instance)
217220
manager = getattr(instance, self.manager_name)
218221
attrs = {}
219222
for field in instance._meta.fields:
220223
attrs[field.attname] = getattr(instance, field.attname)
221224
manager.create(history_date=history_date, history_type=type,
222225
history_user=history_user, **attrs)
223226

227+
def get_history_user(self, instance):
228+
"""Use hints from the instance and middleware to identify the
229+
user making the change.
230+
231+
"""
232+
try:
233+
return instance._history_user
234+
except AttributeError:
235+
try:
236+
return self.thread.request.user
237+
except AttributeError:
238+
return
239+
224240

225241
class ForeignKeyMixin(object):
226242
def get_attname(self):

simple_history/tests/tests/test_admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def test_history_form(self):
114114
self.assertEqual(poll.question, "what?")
115115
self.assertEqual(poll.pub_date, tomorrow)
116116
self.assertEqual([p.history_user for p in Poll.history.all()],
117-
[self.user, None, None])
117+
[self.user] * 3)
118118

119119
def test_history_user_on_save_in_admin(self):
120120
self.login()

0 commit comments

Comments
 (0)