Skip to content

Instantly share code, notes, and snippets.

@jsanchezpando
Created December 20, 2012 09:38
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jsanchezpando/4344176 to your computer and use it in GitHub Desktop.
Save jsanchezpando/4344176 to your computer and use it in GitHub Desktop.
Simple Django super class to track user and save creator and modifier of a Model.
from myapp.utils import set_current_user
class CurrentUserMiddleware:
def process_request(self, request):
set_current_user(getattr(request, 'user', None))
from django.db import models
from django.contrib.auth.models import User
from myapp.utils import get_current_user
class FollowUserModel(models.Model):
created_at = models.ForeignKey(auto_now_add=True)
modified_at = models.ForeignKey(auto_now=True)
created_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_created')
modified_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_modified')
def save(self, *args, **kwargs):
user = get_current_user()
if user and user.is_authenticated():
self.modified_by = user
if not self.id:
self.created_by = user
super(FollowUserModel, self).save(*args, **kwargs)
class Meta:
abstract = True
MIDDLEWARE_CLASSES = (
# ...
'myapp.middleware.CurrentUserMiddleware',
)
import threading
_thread_locals = threading.local()
def set_current_user(user):
_thread_locals.user=user
def get_current_user():
return getattr(_thread_locals, 'user', None)
@jlaso
Copy link

jlaso commented Feb 27, 2018

Hey, well done!

I do think that two fields are wrong:
created_at = models.ForeignKey(auto_now_add=True)
modified_at = models.ForeignKey(auto_now=True)

For me, that works:
created_at = models.DateField(auto_now_add=True)
modified_at = models.DateField(auto_now=True)

@KrYpTeD974
Copy link

KrYpTeD974 commented Nov 21, 2018

Also according to : https://stackoverflow.com/questions/907695/in-a-django-model-custom-save-method-how-should-you-identify-a-new-object/35647389#35647389
it is better to use:

if self._state.adding:
    self.created_by = user

In some cases models don't have self.id or self.pk:

  • When the primary field is a UUID
  • On a OneToOne relationship

Also, I would suggest removing the user from the local thread after the request has been processed.
I had some tests that failed because they all share the same local thread when launch directly from the test class.

class CurrentUserMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):

        set_current_user(getattr(request, 'user', None))

        response = self.get_response(request)

        remove_current_user()
        # Code to be executed for each request/response after
        # the view is called.

        return response
def remove_current_user():
    _thread_locals.user = None

@gwsampso
Copy link

gwsampso commented Feb 6, 2019

@KrYpTeD974

are you able to provide your complete files? please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment