Created
December 20, 2012 09:38
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from myapp.utils import set_current_user | |
class CurrentUserMiddleware: | |
def process_request(self, request): | |
set_current_user(getattr(request, 'user', None)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MIDDLEWARE_CLASSES = ( | |
# ... | |
'myapp.middleware.CurrentUserMiddleware', | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
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
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
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)