在Django 1.9 (Python 3.4)中使用 GenericStackedInline 我想在保存我的模型之前访问请求对象在Django 管理员。
使用MediaItemAdmin
时,我可以在运行obj.save()
之前拦截保存功能,如下例所示:
admin.py
class StuffAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
# Do some stuff here like obj.user = request.user before saving.
obj.save()
然而,相同的行为或“' hook'使用GenericStackedInline
无法使用。它似乎直接调用模型保存方法:
admin.py
class StuffAdmin(GenericStackedInline):
model = StuffModel
def save_model(self, request, obj, form, change):
print("I'm never run :(")
obj.save()
据我所知GenericStackedInline
继承自form
所以我也尝试过使用表单并覆盖它,如下例所示:
admin.py
class StuffAdmin(GenericStackedInline):
model = StuffModel
form = StuffForm
class StuffForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(StuffForm, self).__init__(*args, **kwargs)
def save_model(self, request, obj, form, change):
print("Still not run!(")
obj.save()
def save_form(self, request, obj, form, change):
print("Work already!")
obj.save()
我搜索过stackoverflow,但大多数都没有回复,如accessing request object within a django admin inline model所示,或者说使用init
来执行类似self.request = kwargs.pop('request')
的操作,但request
永远不会在这里传递,正确?
无论如何,任何想法如何在调用模型save()之前调用请求对象并更新我的实例?
答案 0 :(得分:3)
保存“内联”的方法是ModelAdmin
的一部分,而不是InlineModelAdmin
。
class BarInline(GenericStackedInline):
model = Bar
class FooModelAdmin(ModelAdmin):
model = Foo
inlines = [BarInline]
def save_formset(self, request, form, formset, change):
"""
`form` is the base Foo form
`formset` is the ("Bar") formset to save
`change` is True if you are editing an existing Foo,
False if you are creating a new Foo
"""
if formset_matches_your_inline_or_some_requirement(formset):
do_something_with(request)
super().save_formset(request, form, formset, change)
如果你想检查formset是否是BarInline
的formset,你可以这样做:
class BarInline(GenericStackedInline):
model = Bar
def get_formset(self, *args, **kwargs):
formset = super().get_formset(*args, **kwargs)
formset.i_come_from_bar_inline = True
return formset
class FooModelAdmin(ModelAdmin):
model = Foo
inlines = [BarInline]
def save_formset(self, request, form, formset, change):
if getattr(formset, 'i_come_from_bar_inline', False):
do_something_with(request)
super().save_formset(request, form, formset, change)
甚至更好,让它变得通用:
class BarInline(GenericStackedInline):
model = Bar
def pre_save_formset(self, request, form, model_admin, change):
"""Do something here with `request`."""
class FooModelAdmin(ModelAdmin):
model = Foo
inlines = [BarInline]
def save_formset(self, request, form, formset, change):
if hasattr(formset, 'pre_save_formset'):
formset.pre_save_formset(request, form, self, change)
super().save_formset(request, form, formset, change)
if hasattr(formset, 'post_save_formset'):
formset.post_save_formset(request, form, self, change)
如果您需要在每个表单保存之前而不是在每个表单集之前对请求执行某些操作,则必须使用自己的Form和FormSet将请求通过formset传播到表单:
from django.forms import ModelForm
from django.forms.models import BaseInlineFormSet
class BarForm(ModelForm):
model = Bar
def __init__(self, *args, **kwargs):
request = kwargs.pop('request', None)
super().__init__(*args, **kwargs)
self.request = request
def save(self, commit=True):
print(self.request)
print(self.instance)
obj = super().save(False) # Get object but don't save it
do_something_with(self.request, obj)
if commit:
obj.save()
self.save_m2m()
return obj
class BarFormSet(BaseInlineFormSet):
@property
def request(self):
return self._request
@request.setter
def request(self, request):
self._request = request
for form in self.forms:
form.request = request
class BarInline(GenericStackedInline):
codel = Bar
form = BarForm
formset = BarFormSet
class FooModelAdmin(ModelAdmin):
inlines = [BarInline]
def _create_formsets(self, request, obj, change):
formsets, inline_instances = super()._create_formsets(request, obj, change)
for formset in formsets:
formset.request = request
return formsets, inline_instances
根据你的用例,save方法也可能看起来像这样:
class BarForm(ModelForm):
model = Bar
def save(self, commit=True):
do_something_with(self.request, self.instance)
return super().save(commit) # Get object but don't save it
答案 1 :(得分:1)
管理员课程不会从表格中继承;他们包含表单。并且ModelForms没有save_model
或save_form
方法,他们只有save
方法。完全可以覆盖该方法,但它不接受request
;您还需要覆盖__init__
以接受该参数并将其从modeladmin的get_form_kwargs
方法中传入。