I have a model that has a user
field that needs to be auto-populated from the currently logged in user. I can get it working as specified here if the user
field is in a standard ModalAdmin, but if the model I'm working with is in an InlineModelAdmin
and being saved from the record of another model inside the Admin, it won't take.
Here's what I think is the best solution. Took me a while to find it... this answer gave me the clues: https://stackoverflow.com/a/24462173/2453104
On your admin.py:
class YourInline(admin.TabularInline):
model = YourInlineModel
formset = YourInlineFormset
def get_formset(self, request, obj=None, **kwargs):
formset = super(YourInline, self).get_formset(request, obj, **kwargs)
formset.request = request
return formset
On your forms.py:
class YourInlineFormset(forms.models.BaseInlineFormSet):
def save_new(self, form, commit=True):
obj = super(YourInlineFormset, self).save_new(form, commit=False)
# here you can add anything you need from the request
obj.user = self.request.user
if commit:
obj.save()
return obj
I know I'm late to the party, but here's my situation and what I came up with, which might be useful to someone else in the future.
I have 4 inline models that need the currently logged in user.
created_by
type field. (set once on creation)closed_by
type field. (only set on condition)I used the answer provided by rafadev and made it into a simple mixin which enables me to specify the user field name elsewhere.
from django.forms.models import BaseInlineFormSet
class SetCurrentUserFormset(forms.models.BaseInlineFormSet):
"""
This assume you're setting the 'request' and 'user_field' properties
before using this formset.
"""
def save_new(self, form, commit=True):
"""
This is called when a new instance is being created.
"""
obj = super(SetCurrentUserFormset, self).save_new(form, commit=False)
setattr(obj, self.user_field, self.request.user)
if commit:
obj.save()
return obj
def save_existing(self, form, instance, commit=True):
"""
This is called when updating an instance.
"""
obj = super(SetCurrentUserFormset, self).save_existing(form, instance, commit=False)
setattr(obj, self.user_field, self.request.user)
if commit:
obj.save()
return obj
class SetCurrentUserFormsetMixin(object):
"""
Use a generic formset which populates the 'user_field' model field
with the currently logged in user.
"""
formset = SetCurrentUserFormset
user_field = "user" # default user field name, override this to fit your model
def get_formset(self, request, obj=None, **kwargs):
formset = super(SetCurrentUserFormsetMixin, self).get_formset(request, obj, **kwargs)
formset.request = request
formset.user_field = self.user_field
return formset
class YourModelInline(SetCurrentUserFormsetMixin, admin.TabularInline):
model = YourModel
fields = ['description', 'closing_user', 'closing_date']
readonly_fields = ('closing_user', 'closing_date')
user_field = 'closing_user' # overriding only if necessary
...as this mixin code will set the currently logged in user everytime for every user. If you need the field to be populated only on creation or on specific update, you need to deal with this in your model save method. Here are some examples:
class UserOnlyOnCreationExampleModel(models.Model):
# your fields
created_by = # user field...
comment = ...
def save(self, *args, **kwargs):
if not self.id:
# on creation, let the user field populate
self.date = datetime.today().date()
super(UserOnlyOnCreationExampleModel, self).save(*args, **kwargs)
else:
# on update, remove the user field from the list
super(UserOnlyOnCreationExampleModel, self).save(update_fields=['comment',], *args, **kwargs)
Or if you only need the user if a particular field is set (like boolean field closed
) :
def save(self, *args, **kwargs):
if self.closed and self.closing_date is None:
self.closing_date = datetime.today().date()
# let the closing_user field set
elif not self.closed :
self.closing_date = None
self.closing_user = None # unset it otherwise
super(YourOtherModel, self).save(*args, **kwargs) # Call the "real" save() method.
This code could probably be made way more generic as I'm fairly new to python but that's what will be in my project for now.
Only the save_model
for the model you're editing is executed, instead you will need to use the post_save
signal to update inlined data.
(Not really a duplicate, but essentially the same question is being answered in Do inline model forms emmit post_save signals? (django))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With