我的模型具有user
字段,需要从当前登录的用户自动填充。如果user
字段位于标准ModalAdmin中,但是如果我正在使用的模型位于here并且从记录中保存,我可以按照指定InlineModelAdmin
运行它管理员内部的另一个模型,它不会采取。
答案 0 :(得分:13)
这是我认为最好的解决方案。花了一段时间才找到它...这个答案给了我线索:https://stackoverflow.com/a/24462173/2453104
在你的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
在您的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
答案 1 :(得分:5)
我知道我迟到了,但这是我的情况以及我想出的事情,这对未来的其他人可能有用。
我有4个需要当前登录用户的内联模型。
created_by
类型字段。 (在创作时设置一次)closed_by
类型字段。 (仅限条件)我使用rafadev提供的答案并将其变为简单的mixin ,这使我能够在其他地方指定用户字段名称。
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
...因为这个mixin代码将每次为每个用户设置当前登录的用户。如果您只需要在创建或特定更新时填充该字段,则需要在模型保存方法中处理此问题。以下是一些例子:
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)
或者,如果您在设置特定字段时只需要用户(如布尔字段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.
这段代码可能会更通用,因为我对python还不熟悉,但这就是我现在的项目。
答案 2 :(得分:2)
只执行您正在编辑的模型的save_model
,而您需要使用post_save
信号来更新内联数据。
(并非真的重复,但基本上同样的问题正在Do inline model forms emmit post_save signals? (django))
中得到解答答案 3 :(得分:1)
我在内联模型中尝试填充的用户字段存在类似问题。在我的例子中,父模型也定义了用户字段,因此我在子模型上覆盖了save
,如下所示:
class inline_model:
parent = models.ForeignKey(parent_model)
modified_by = models.ForeignKey(User,editable=False)
def save(self,*args,**kwargs):
self.modified_by = self.parent.modified_by
super(inline_model,self).save(*args,**kwargs)
用户字段最初是在父模型上自动填充的,方法是在ModelAdmin中覆盖父模型的save_model并指定
obj.modified_by = request.user
请记住,如果您还有一个独立的子模型管理页面,您将需要一些其他机制来保持父和子的modified_by字段同步(例如,您可以覆盖孩子的save_model
在调用孩子的save
之前,ModelAdmin并更新/保存父母的modified_by字段。
如果用户不在父模型中,我还没有找到一个好方法来处理这个问题。我不知道如何使用信号检索request.user
(例如post_save
),但也许其他人可以提供更多详细信息。
答案 4 :(得分:0)
其他型号是否会保存用户?在这种情况下,您可以使用post_save
信号将该信息添加到内联模型的集合中。
答案 5 :(得分:0)
您是否尝试在管理员中实施自定义验证,如documentation中所述?覆盖模型表单上的clean_user()函数可能会为您提供帮助。
另一个更为复杂的选择浮现在脑海中。您可以覆盖呈现更改表单的管理模板。覆盖更改表单将允许您构建自定义模板标记,将登录用户传递给ModelForm。然后,您可以在自动设置用户的模型表单上编写自定义 init 功能。 This answer提供了一个如何做到这一点的好例子,就像你在问题中引用的b-list上的链接一样。