Django admin 不同的内联用于更改和添加视图

Posted

技术标签:

【中文标题】Django admin 不同的内联用于更改和添加视图【英文标题】:Django admin different inlines for change and add view 【发布时间】:2011-01-15 04:24:33 【问题描述】:

我需要单独的视图来添加和更改页面。在添加页面中,我想从内联表单集中排除一些字段。我准备了两个 TabularInline 类,其中一个包含属性“排除”。我尝试按如下方式使用它们:

class BoxAdmin(admin.ModelAdmin):
    def change_view(self, request, obj_id):
        self.inlines=[ItemChangeInline,]
        return super(BoxAdmin, self).change_view(self.request, obj_id)
    def add_view(self, request):
        self.inlines=[ItemAddInline,]
        return super(BoxAdmin, self).add_view(self, request)

没有效果(根本没有显示内联)。

【问题讨论】:

【参考方案1】:

它适用于 Django 1.5+ 并且看起来很优雅:

// admin.py
class BoxAdmin(ModelAdmin):

    inlines = ()

    def change_view(self, request, object_id, form_url='', extra_context=None):
        self.inlines = (ItemChangeInline, )
        return super(BoxAdmin, self).change_view(request, object_id)

    def add_view(self, request, form_url='', extra_context=None):
        self.inlines = (ItemAddInline, )
        return super(BoxAdmin, self).add_view(request)

希望对大家有用

【讨论】:

我逐字使用它并且它有效,但我用return super(BoxAdmin, self).change_view(request, object_id, form_url, extra_context)return super(BoxAdmin, self).add_view(request, form_url, extra_context)替换了两个返回【参考方案2】:

这是似乎可以工作的代码:

class BoxAdmin(admin.ModelAdmin):
   def change_view(self, request, obj_id):
        self.inlines=[ItemChangeInline,]
        for inline_class in self.inlines:
            inline_instance = inline_class(self.model, self.admin_site)
            self.inline_instances.append(inline_instance)
        return super(BoxAdmin, self).change_view(request, obj_id)
    def add_view(self, request):
        self.inlines=[ItemAddInline,]
        for inline_class in self.inlines:
            inline_instance = inline_class(self.model, self.admin_site)
            self.inline_instances.append(inline_instance)
        return super(BoxAdmin, self).add_view(request)

但是,这看起来不优雅,因为这部分:

            for inline_class in self.inlines:
            inline_instance = inline_class(self.model, self.admin_site)
            self.inline_instances.append(inline_instance)

是 admin.ModelAdmin 的 init 方法的复制粘贴(因此它运行两次)。

【讨论】:

【参考方案3】:

为什么在 add_view 中有 .add_view(self, request) 而在更改视图中有 .change_view(self.request, ..)?我相信,您不需要在 add_view 中使用 self,因为您使用的是 super。

【讨论】:

【参考方案4】:

我遇到了一种情况,我需要根据您为给定故事使用的管理站点显示内联。

扩展 alekwisnia 的答案,我能够使用以下代码获得适用于 Django 1.3 的动态内联:

在 highlight/admin.py 中

class HighlightInline(generic.GenericTabularInline):
    model = Highlight
    extra = 1
    max_num = 4
    fields = ('order', 'highlight')
    template = 'admin/highlights/inline.html'

class HighlightAdmin(admin.ModelAdmin):
    def regulate_highlight_inlines(self):
        highlights_enabled = Setting.objects.get_or_default('highlights_enabled', default='')
        highlight_inline_instance = HighlightInline(self.model, self.admin_site)
        highlight_found = any(isinstance(x, HighlightInline) for x in self.inline_instances)
        if highlights_enabled.strip().lower() == 'true':
            if not highlight_found:
                self.inline_instances.insert(0, highlight_inline_instance)
        else:
            if highlight_found:
                self.inline_instances.pop(0)
        print self.inline_instances

    def change_view(self, request, object_id, form_url='', extra_context=None):
        self.regulate_highlight_inlines()
        return super(HighlightAdmin, self).change_view(request, object_id)

    def add_view(self, request, form_url='', extra_context=None):
        self.regulate_highlight_inlines()   
        return super(HighlightAdmin, self).add_view(request, form_url, extra_context)

在故事/admin.py中

class StoryAdmin(HighlightAdmin):

需要注意的一点是,我不仅仅是在操作内联类 (HighlightInline),而是在更改内联实例 (HighlightInline(self.model, self.admin_site))。这是因为 django 在 admin 类的初始构建过程中,已经根据内联类列表构建了内联实例列表。

【讨论】:

【参考方案5】:

Django 1.3 的另一种解决方案

class BoxAdmin(admin.ModelAdmin):

    def change_view(self, request, object_id, form_url='', extra_context=None):
        self.inline_instances = [ItemChangeInline(self.model, self.admin_site)]
        return super(BoxAdmin, self).change_view(request, object_id, extra_context)

    def add_view(self, request, form_url='', extra_context=None):
        self.inline_instances = [ItemAddInline(self.model, self.admin_site)]
        return super(BoxAdmin, self).add_view(request, form_url, extra_context)

【讨论】:

【参考方案6】:

受到你们回答的启发, 我能够向 admin.site 添加更多自定义视图。

很多时候,只是想要addchange 不同设置的页面,而不是真正的额外浏览量

# admin.py
class FooAdmin(admin.ModelAdmin):
    ....
    def edit_tag(self, obj):              # add a Link tag to change-list page
        return mark_safe('<a href="?edit=True">Edit</a>'.format(obj.get_absolute_url()))

    edit_tag.short_description = u'Extra Action'

    def change_view(self, request, object_id, form_url='', extra_context=None):
        if request.GET.get('edit', False):
            self.readonly_fields = (
                'total_amount',
            )
            self.inlines = []
        else:
            self.readonly_fields = (
                'name', 'client', 'constructor', 'total_amount'
            )
            self.inlines = [TransactionInline]
        return super(ProjectAdmin, self).change_view(request, object_id)

    def add_view(self, request, form_url='', extra_context=None):
        self.readonly_fields = (
            'total_amount',
        )
        self.inlines = []
        return super(ProjectAdmin, self).add_view(request)

在此之后,我将拥有三个视图:

    添加视图 - 无需内联表单集,无需添加相关对象。

    更改视图 1 - 使用内联表单集,仅用于添加内联数据(相关对象),对象的字段是只读的。

    更改视图 2 - 没有内联表单集,仅用于更改对象。

真的很简单,我们可以做得更多,谢谢大家。

【讨论】:

以上是关于Django admin 不同的内联用于更改和添加视图的主要内容,如果未能解决你的问题,请参考以下文章

Django Admin -> 更改字段顺序,包括内联字段

在 Django admin 中添加内联多对多对象

Django Admin Cookbook-23如何在Django admin中添加嵌套的内联

Django Admin,我的表的所有内容都没有显示和内联问题

如何在 django admin 上添加只读内联

Django Admin:动态添加内联