40👍
Can’t be done. The current user is only available via the request, which is not available when using purely model functionality. Access the user in the view somehow.
12👍
You can do that with the help of middleware. Create get_request.py
in your app. Then
from threading import current_thread
from django.utils.deprecation import MiddlewareMixin
_requests = {}
def current_request():
return _requests.get(current_thread().ident, None)
class RequestMiddleware(MiddlewareMixin):
def process_request(self, request):
_requests[current_thread().ident] = request
def process_response(self, request, response):
# when response is ready, request should be flushed
_requests.pop(current_thread().ident, None)
return response
def process_exception(self, request, exception):
# if an exception has happened, request should be flushed too
_requests.pop(current_thread().ident, None)
Then add this middleware to your settings:
MIDDLEWARE = [
....
'<your_app>.get_request.RequestMiddleware',
]
Then add import to your signals:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from <your_app>.get_request import current_request
# CORE - SIGNALS
# Core Signals will operate based on post
def after_save_handler_attr_audit_obj(sender, **kwargs):
print(Current User, current_request().user)
print User.get_profile()
if hasattr(kwargs['instance'], 'audit_obj'):
if kwargs['created']:
kwargs['instance'].audit_obj.create(operation="INSERT", operation_by=**USER.ID**).save()
else:
kwargs['instance'].audit_obj.create(operation="UPDATE").save()
# Connect the handler with the post save signal - Django 1.2
post_save.connect(after_save_handler_attr_audit_obj, dispatch_uid="core.models.audit.new")
- [Django]-Django import error – No module named core.management
- [Django]-Annotate a queryset with the average date difference? (django)
- [Django]-Django ORM – objects.filter() vs. objects.all().filter() – which one is preferred?
10👍
I was able to do it by inspecting the stack and looking for the view then looking at the local variables for the view to get the request. It feels like a bit of a hack, but it worked.
import inspect, os
@receiver(post_save, sender=MyModel)
def get_user_in_signal(sender, **kwargs):
for entry in reversed(inspect.stack()):
if os.path.dirname(__file__) + '/views.py' == entry[1]:
try:
user = entry[0].f_locals['request'].user
except:
user = None
break
if user:
# do stuff with the user variable
- [Django]-Django auto_now and auto_now_add
- [Django]-Django – view sql query without publishing migrations
- [Django]-Django + Ajax
9👍
Ignacio is right. Django’s model signals are intended to notify other system components about events associated with instances and their respected data, so I guess it’s valid that you cannot, say, access request data from a model post_save
signal, unless that request data was stored on or associated with the instance.
I guess there are lots of ways to handle it, ranging from worse to better, but I’d say this is a prime example for creating class-based/function-based generic views that will automatically handle this for you.
Have your views that inherit from CreateView
, UpdateView
or DeleteView
additionally inherit from your AuditMixin
class if they handle verbs that operate on models that need to be audited. The AuditMixin
can then hook into the views that successfully create\update\delete objects and create an entry in the database.
Makes perfect sense, very clean, easily pluggable and gives birth to happy ponies. Flipside? You’ll either have to be on the soon-to-be-released Django 1.3 release or you’ll have to spend some time fiddlebending the function-based generic views and providing new ones for each auditing operation.
- [Django]-Django {% if forloop.first %} question
- [Django]-Missing Table When Running Django Unittest with Sqlite3
- [Django]-What is a context in Django?
7👍
Why not adding a middleware with something like this :
class RequestMiddleware(object):
thread_local = threading.local()
def process_request(self, request):
RequestMiddleware.thread_local.current_user = request.user
and later in your code (specially in a signal in that topic) :
thread_local = RequestMiddleware.thread_local
if hasattr(thread_local, 'current_user'):
user = thread_local.current_user
else:
user = None
- [Django]-How to force a user logout in Django?
- [Django]-AccessDenied when calling the CreateMultipartUpload operation in Django using django-storages and boto3
- [Django]-Get distinct values of Queryset by field
6👍
For traceability add two attributes to your Model(created_by
and updated_by
), in “updated_by” save the last user who modified the record. Then in your signal you have the user:
models.py:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
created_by = models. (max_length=100)
updated_by = models. (max_length=100)
views.py
p = Question.objects.get(pk=1)
p.question_text = 'some new text'
p.updated_by = request.user
p.save()
signals.py
@receiver(pre_save, sender=Question)
def do_something(sender, instance, **kwargs):
try:
obj = Question.objects.get(pk=instance.pk)
except sender.DoesNotExist:
pass
else:
if not obj.user == instance.user: # Field has changed
# do something
print('change: user, old=%s new=%s' % (obj.user, instance.user))
- [Django]-Django gives Bad Request (400) when DEBUG = False
- [Django]-Speeding up Django Testing
- [Django]-Django optional URL parameters
6👍
You could also use django-reversion for this purpose, e.g.
from reversion.signals import post_revision_commit
import reversion
@receiver(post_save)
def post_revision_commit(sender, **kwargs):
if reversion.is_active():
print(reversion.get_user())
Read more on their API https://django-reversion.readthedocs.io/en/stable/api.html#revision-api
- [Django]-Django request get parameters
- [Django]-Django – Clean permission table
- [Django]-Redis Python – how to delete all keys according to a specific pattern In python, without python iterating
4👍
You can do a small hack by overriding you model save()
method and setting the user on the saved instance as additional parameter. To get the user I used get_current_authenticated_user()
from django_currentuser.middleware.ThreadLocalUserMiddleware
(see https://pypi.org/project/django-currentuser/).
In your models.py
:
from django_currentuser.middleware import get_current_authenticated_user
class YourModel(models.Model):
...
...
def save(self, *args, **kwargs):
# Hack to pass the user to post save signal.
self.current_authenticated_user = get_current_authenticated_user()
super(YourModel, self).save(*args, **kwargs)
In your signals.py
:
@receiver(post_save, sender=YourModel)
def your_model_saved(sender, instance, **kwargs):
user = getattr(instance, 'current_authenticated_user', None)
PS: Don’t forget to add 'django_currentuser.middleware.ThreadLocalUserMiddleware'
to your MIDDLEWARE_CLASSES
.
- [Django]-Sort order of Django Admin records
- [Django]-Jquery template tags conflict with Django template!
- [Django]-Unable to find a locale path to store translations for file __init__.py
2👍
I imagine you would have figured this out, but I had the same problem and I realised that all the instances I create had a reference to the user that creates them (which is what you are looking for)
- [Django]-How to update an object from edit form in Django?
- [Django]-How do you configure Django for simple development and deployment?
- [Django]-How to access the user profile in a Django template?
0👍
it’s possible i guess.
in models.py
class _M(models.Model):
user = models.ForeignKey(...)
in views.py
def _f(request):
_M.objects.create(user=request.user)
in signals.py
@receiver(post_save, sender=_M)
def _p(sender, instance, created, **kwargs):
user = instance.user
No ?
- [Django]-Django modelform NOT required field
- [Django]-How to get request object in django unit testing?
- [Django]-Django : How can I find a list of models that the ORM knows?
0👍
Request object can be obtained from frame record by inspecting.
import inspect
request = [
frame_record[0].f_locals["request"]
for frame_record in inspect.stack()
if frame_record[3] == "get_response"
][0]
- [Django]-How do I match the question mark character in a Django URL?
- [Django]-Setting Django up to use MySQL
- [Django]-Is Django for the frontend or backend?
0👍
def get_requested_user():
import inspect
for frame_record in inspect.stack():
if frame_record[3] == 'get_response':
request = frame_record[0].f_locals['request']
return request.user
else:
return None
- [Django]-Separating form input and model validation in Django?
- [Django]-Django-reversion and related model
- [Django]-Equivalent of PHP "echo something; exit();" with Python/Django?
-4👍
context_processors.py
from django.core.cache import cache
def global_variables(request):
cache.set('user', request.user)
----------------------------------
in you model
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.core.cache import cache
from news.models import News
@receiver(pre_delete, sender=News)
def news_delete(sender, instance, **kwargs):
user = cache.get('user')
in settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
'web.context_processors.global_variables',
)
- [Django]-How do I do an OR filter in a Django query?
- [Django]-Homepage login form Django
- [Django]-Django ORM – objects.filter() vs. objects.all().filter() – which one is preferred?