Django: How to get current user in admin forms?
Solution 1
Here is what i did recently for a Blog:
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, **kwargs)
form.current_user = request.user
return form
I can now access the current user in my forms.ModelForm
by accessing self.current_user
EDIT: This is an old answer, and looking at it recently I realized the get_form
method should be amended to be:
def get_form(self, request, *args, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, *args, **kwargs)
form.current_user = request.user
return form
(Note the addition of *args
)
Solution 2
Joshmaker's answer doesn't work for me on Django 1.7. Here is what I had to do for Django 1.7:
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, obj=None, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, obj, **kwargs)
form.current_user = request.user
return form
For more details on this method, please see this relevant Django documentation
Solution 3
This use case is documented at ModelAdmin.get_form
[...] if you wanted to offer additional fields to superusers, you could swap in a different base form like so:
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
kwargs['form'] = MySuperuserForm
return super().get_form(request, obj, **kwargs)
If you just need to save a field, then you could just override ModelAdmin.save_model
from django.contrib import admin
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
super().save_model(request, obj, form, change)
Solution 4
I think I found a solution that works for me: To create a ModelForm
Django uses the admin's formfield_for_db_field
-method as a callback.
So I have overwritten this method in my admin and pass the current user object as an attribute with every field (which is probably not the most efficient but appears cleaner to me than using threadlocals:
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(MyAdmin, self).formfield_for_dbfield(db_field, **kwargs)
field.user = kwargs.get('request', None).user
return field
Now I can access the current user object in the forms __init__
with something like:
current_user=self.fields['fieldname'].user
Solution 5
Another way you can solve this issue is by using Django currying which is a bit cleaner than just attaching the request object to the form model.
from django.utils.functional import curry
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, **kwargs)
return curry(form, current_user=request.user)
This has the added benefit making your init method on your form a bit more clear as others will understand that it's being passed as a kwarg and not just randomly attached attribute to the class object before initialization.
class BlogPostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.current_user = kwargs.pop('current_user')
super(BlogPostForm, self).__init__(*args, **kwargs)
Bernhard Vallant
Updated on July 09, 2022Comments
-
Bernhard Vallant almost 2 years
In Django's
ModelAdmin
, I need to display forms customized according to the permissions an user has. Is there a way of getting the current user object into the form class, so that i can customize the form in its__init__
method?I think saving the current request in a thread local would be a possibility but this would be my last resort because I'm thinking it is a bad design approach.
-
hcalves about 12 yearsThis is an
AttributeError
:kwargs.get('request', None).user
-
maggie about 5 yearsIf
form = BlogPostForm
, what shallget_form
actually return? A BlogPostForm or the ModelForm of the parent class of BlogPostAdmin...? How will BlogPostForm get used if you use get_form? -
zbyte almost 5 yearsI liked this but sadly doesn't work as downstream the code expects a form class and not a curry function. Doing this results in the following error "'function' object has no attribute 'base_fields'"
-
Alexis R almost 3 yearsCould one add it to the kwargs directly?
-
Oduvan almost 2 years@AndrewBarrett not for class, and not dangerous
-
Oduvan almost 2 yearshow the code-snippet is different from the one shared by Joshmaker?
-
Joshmaker almost 2 years@AndrewBarrett this should be safe because we are attaching the
current_user
to a form instance and a new one is newly created for each request (hencerequest
being passed as a variable to this method). -
Andrew Barrett almost 2 years@Joshmaker Yeah for sure, not sure what I was smoking two years ago, have deleted my comment.