-
-
Save mindlace/3918300 to your computer and use it in GitHub Desktop.
"""Add user created_by and modified_by foreign key refs to any model automatically. | |
Almost entirely taken from https://github.com/Atomidata/django-audit-log/blob/master/audit_log/middleware.py""" | |
from django.db.models import signals | |
from django.utils.functional import curry | |
class WhodidMiddleware(object): | |
def process_request(self, request): | |
if not request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): | |
if hasattr(request, 'user') and request.user.is_authenticated(): | |
user = request.user | |
else: | |
user = None | |
mark_whodid = curry(self.mark_whodid, user) | |
signals.pre_save.connect(mark_whodid, dispatch_uid = (self.__class__, request,), weak = False) | |
def process_response(self, request, response): | |
signals.pre_save.disconnect(dispatch_uid = (self.__class__, request,)) | |
return response | |
def mark_whodid(self, user, sender, instance, **kwargs): | |
if not getattr(instance, 'created_by_id', None): | |
instance.created_by = user | |
if hasattr(instance,'modified_by_id'): | |
instance.modified_by = user |
How to use this?
Fantastic. It really helps me a lot.
October 2016. With Django==1.10.2 and djangorestframework==3.4.7 it still works with no modification whatsoever. Thanks.
Can you provide an example to use within a model?
I keep coming back to this gist on projects, it's a good DRY solution to the problem.
If anyone needs it to also work with Django REST Framework (which uses its own auth system), you can manually fire the DRF backends you use there by swapping the user =
lines above out for something like this which tries the same but falls back to DRF if unauthed:
from rest_framework import authentication
try:
user = request.user
if not user.is_authenticated():
auth = authentication.BasicAuthentication().authenticate(request)
if auth:
user = auth[0]
else:
user = None
except (authentication.exceptions.AuthenticationFailed, KeyError):
user = None
Modify to suit your needs aka your backends which are hopefully not basic auth – if anyone can be bothered I imagine this can be improved to pull the backends you use out of settings.py
without too much difficulty.
Update for Django 2.0, doc
from django.db.models import signals
from django.utils.functional import curry
class WhodidMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
if hasattr(request, 'user') and request.user.is_authenticated:
user = request.user
else:
user = None
mark_whodid = curry(self.mark_whodid, user)
signals.pre_save.connect(
mark_whodid,
dispatch_uid=(self.__class__, request,),
weak=False)
response = self.get_response(request)
signals.pre_save.disconnect(dispatch_uid=(self.__class__, request,))
return response
def mark_whodid(self, user, sender, instance, **kwargs):
if not getattr(instance, 'created_by_id', None):
instance.created_by = user
if hasattr(instance, 'modified_by_id'):
instance.modified_by = user
I am not sure that this method is thread safe. According to the signal source code, Signal are shared by threads. Or am I missing something?
Can someone explain How to use above code?
Brilliant. Thanks!