74👍
Here is what i did recently for a Blog:
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, *args, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, *args, **kwargs)
form.current_user = request.user
return form
I can now access the current user in my forms.ModelForm
by accessing self.current_user
22👍
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
- [Django]-Django 1.11 Annotating a Subquery Aggregate
- [Django]-Accepting email address as username in Django
- [Django]-Django – Where are the params stored on a PUT/DELETE request?
9👍
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)
- [Django]-Where is my Django installation?
- [Django]-"Too many values to unpack" Exception
- [Django]-How to add custom search box in Django-admin?
5👍
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
- [Django]-How to add clickable links to a field in Django admin?
- [Django]-One-to-many inline select with django admin
- [Django]-PicklingError: Can't pickle <class 'decimal.Decimal'>: it's not the same object as decimal.Decimal
4👍
stumbled upon same thing and this was first google result on my page.Dint helped, bit more googling and worked!!
Here is how it works for me (django 1.7+) :
class SomeAdmin(admin.ModelAdmin):
# This is important to have because this provides the
# "request" object to "clean" method
def get_form(self, request, obj=None, **kwargs):
form = super(SomeAdmin, self).get_form(request, obj=obj, **kwargs)
form.request = request
return form
class SomeAdminForm(forms.ModelForm):
class Meta(object):
model = SomeModel
fields = ["A", "B"]
def clean(self):
cleaned_data = super(SomeAdminForm, self).clean()
logged_in_email = self.request.user.email #voila
if logged_in_email in ['abc@abc.com']:
raise ValidationError("Please behave, you are not authorised.....Thank you!!")
return cleaned_data
- [Django]-Django templates: verbose version of a choice
- [Django]-Django connection to postgres by docker-compose
- [Django]-Django – Get only date from datetime.strptime
4👍
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)
- [Django]-A better way to restart/reload Gunicorn (via Upstart) after 'git pull'ing my Django projects
- [Django]-How to update an existing Conda environment with a .yml file
- [Django]-Django: Redirect to previous page after login
0👍
Use this function which acts as a proxy to the form class, allowing us to inject the request, on the form instance, so that we can access it in the clean methods.
By using a solution like the below one (get_form_class_with_request), you isolate the request injection to the moment of form instance creation. This ensures that each form instance has its own request data, reducing the risk of conflicts and unexpected behavior caused by shared state.
def get_form_class_with_request(
form_class: type[forms.ModelForm], request: HttpRequest
) -> Callable[[tuple[Any, ...], dict[str, Any]], ModelForm]:
def init_form(*args, **kwargs) -> ModelForm:
form_instance = form_class(*args, **kwargs)
form_instance.request = request
form_instance.current_user = request.user
return form_instance
init_form.base_fields = form_class.base_fields
return init_form
class CustomModelAdmin(admin.ModelAdmin):
form = YourForm
def get_form(self, request, *args, **kwargs):
form = super().get_form(request, *args, **kwargs)
form_proxy = get_form_class_with_request(form, request)
return form_proxy
Overall, it’s a best practice to keep request-specific data within the request scope and avoid storing it directly in form classes or other shared objects to maintain proper isolation and prevent potential issues.
- [Django]-Reducing Django Memory Usage. Low hanging fruit?
- [Django]-Gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3> django
- [Django]-POST jQuery array to Django