给定名为MainModel
和RelatedModel
的模型,其中后者的ForeignKey
字段为MainModel
:
class MainModel(models.Model):
name = models.CharField(max_length=50)
type = models.BooleanField()
class RelatedModel1(models.Model):
main = models.ForeingKey(MainModel):
name = models.CharField(max_length=50)
class RelatedModel2(models.Model):
main = models.ForeingKey(MainModel):
name = models.CharField(max_length=50)
和相应的ModelAdmin类:
class RelatedModel1InlineAdmin(admin.TabularInline):
model = RelatedModel1
class RelatedModel2InlineAdmin(admin.TabularInline):
model = RelatedModel2
class MainModel(admin.ModelAdmin):
inlines = [RelatedModel1, RelatedModel2]
这是默认行为,你得到两个内联,每个相关模型一个。问题是如何在创建MainModel
实例(ModelAdmin
的{{1}})时完全隐藏所有内联,并在显示add_view
时显示内联RelatedModel1
个实例的type
字段为MainModel
,并在True
时显示RelatedModel2
的内联。
我打算为False
属性创建descriptor,但我意识到我需要访问正在编辑的对象实例,但它会作为参数传递。
任何帮助?
谢谢!
答案 0 :(得分:4)
@Yuji' Tomita' Tomitayou的想法很好,我有同样的但是一旦尝试,我意识到你还必须删除self.inlines
中的特定密钥,因为在change_view
和add_view
方法self.get_inline_instances(request)
之前调用get_formsets()
。因此,我将内联处理移至get_form()
方法。
以下是我成功的方式:
class SampleAdmin(ModelAdmin):
inlines = []
def get_inlines(self):
return [SampleInline, SampleInline2]
def get_form(self, request, obj=None, **kwargs):
# due to django admin form fields caching you must
# redefine inlines on every `get_form()` call
if (obj): self.inlines = self.get_inlines()
for inline in self.inlines:
# Here change condition based on your needs and manipulate
# self.inlines as you like (remove, change, etc).
# I used inline.__name__ to detect if this is correct inline
# for my obj
if obj.CONDITION:
self.inlines.remove(inline)
return super(SampleAdmin, self).get_form(request, obj, **kwargs)
答案 1 :(得分:3)
我意识到这个问题有点陈旧,而且代码库有所改变;现在有一个清晰的要点覆盖事物:c1
。你可以这样做:
get_inline_instances
答案 2 :(得分:2)
您只需要在 ModelAdmin 中简单地覆盖 change_view
:
def change_view(self, request, object_id, form_url='', extra_context=None):
obj = self.model.objects.filter(pk=object_id).first()
if not obj:
self.inlines = []
else:
if obj.type is True:
self.inlines = [RelatedModel1InlineAdmin]
else:
self.inlines = [RelatedModel2InlineAdmin]
return super().change_view(request,object_id,form_url=form_url,extra_context=extra_context)
这对我有用。
答案 3 :(得分:1)
从contrib.admin.options.py
偷看看起来你可以覆盖ModelAdmin.get_formsets
。请注意,管理网站会在self.inline_instances
填充__init__
,因此您可能希望关注并不反复实例化您的内联。我不确定它有多贵:)
def get_formsets(self, request, obj=None):
if not obj:
return [] # no inlines
elif obj.type == True:
return [MyInline1(self.model, self.admin_site).get_formset(request, obj)]
elif obj.type == False:
return [MyInline2(self.model, self.admin_site).get_formset(request, obj)]
# again, not sure how expensive MyInline(self.model, self.admin_site) is.
# the admin does this once. You could instantiate them and store them on the
# admin class somewhere to reference instead.
原始管理员get_formsets
使用生成器 - 您也可以更接近地模仿原始版本:
def get_formsets(self, request, obj=None):
for inline in self.inline_instances:
yield inline.get_formset(request, obj)
答案 4 :(得分:1)
这对我来说在寻找旧帖子中同一问题的答案时起了作用。
根据darklow的回答,我认为您可以完全覆盖get_inline_instances
,并根据您的类型添加额外的检查。
在模型中添加布尔类型检查方法
class MainModel(models.Model):
name = models.CharField(max_length=50)
type = models.BooleanField()
def is_type1(self):
return type=="some value"
def is_type2(self):
return type=="some value"
在类型检查中添加内联实例 - 只需将get_inline_insances方法从父类复制并粘贴到admin.ModelAdmin类中,然后添加if块以检查模型类型,如下所示
class MyModelAdmin(admin.ModelAdmin):
inlines = [RelatedModel1, RelatedModel2]
def get_inline_instances(self, request, obj=None):
inline_instances = []
if not obj:
return []
for inline_class in self.inlines:
inline = inline_class(self.model, self.admin_site)
if request:
if not (inline.has_add_permission(request) or
inline.has_change_permission(request, obj) or
inline.has_delete_permission(request, obj)):
continue
if not inline.has_add_permission(request):
inline.max_num = 0
if obj.is_type1() and isinstance(inline,RelatedModel1InlineAdmin):
inline_instances.append(inline)
if obj.is_type2() and isinstance(inline,RelatedModel2InlineAdmin):
inline_instances.append(inline)
return inline_instances
答案 5 :(得分:0)
这是我在遇到同样问题时编写的一段代码。我想这是一种蛮力的风格,但是非常灵活,应该适合所有情况。
class MyModelAdmin(admin.ModelAdmin):
def __init__(self, *args, **kwargs):
super(MyModelAdmin, self).__init__(*args, **kwargs)
self.inline_instances_hash = {}
for inline_class in self.inlines:
for inline_instance in self.inline_instances:
if isinstance(inline_instance, inline_class):
break
self.inline_instances_hash[inline_class] = inline_instance
def get_inline_instance(self, inline_class):
return self.inline_instances_hash[inline_class]
def get_form(self, request, obj=None, **kwargs):
if obj:
self.inline_instances = []
if self.CONDITION:
self.inline_instances.append(self.get_inline_instance(
THE_INLINE_CLASS_I_WANT))
#...
else:
self.inline_instances = self.inline_instances_hash.values()