Django: Populate user ID when saving a model
Solution 1:
UPDATE 2020-01-02
⚠ The following answer was never updated to the latest Python and Django versions. Since writing this a few years ago packages have been released to solve this problem. Nowadays I highly recommend usingdjango-crum
which implements the same technique but has tests and is updated regularly: https://pypi.org/project/django-crum/
The least obstrusive way is to use a CurrentUserMiddleware
to store the current user in a thread local object:
current_user.py
from threading import local
_user = local()
class CurrentUserMiddleware(object):
def process_request(self, request):
_user.value = request.user
def get_current_user():
return _user.value
Now you only need to add this middleware to your MIDDLEWARE_CLASSES after the authentication middleware.
settings.py
MIDDLEWARE_CLASSES = (
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
'current_user.CurrentUserMiddleware',
...
)
Your model can now use the get_current_user
function to access the user without having to pass the request object around.
models.py
from django.db import models
from current_user import get_current_user
class MyModel(models.Model):
created_by = models.ForeignKey('auth.User', default=get_current_user)
Hint:
If you are using Django CMS you do not even need to define your own CurrentUserMiddleware but can use cms.middleware.user.CurrentUserMiddleware
and the cms.utils.permissions.get_current_user
function to retrieve the current user.
Solution 2:
If you want something that will work both in the admin and elsewhere, you should use a custom modelform. The basic idea is to override the __init__
method to take an extra parameter - request - and store it as an attribute of the form, then also override the save method to set the user id before saving to the database.
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(MyModelForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
kwargs['commit']=False
obj = super(MyModelForm, self).save(*args, **kwargs)
if self.request:
obj.user = self.request.user
obj.save()
return obj
Solution 3:
Daniel's answer won't work directly for the admin because you need to pass in the request object. You might be able to do this by overriding the get_form
method in your ModelAdmin
class but it's probably easier to stay away from the form customisation and just override save_model
in your ModelAdmin
.
def save_model(self, request, obj, form, change):
"""When creating a new object, set the creator field.
"""
if not change:
obj.creator = request.user
obj.save()