【问题标题】:Add button for child model in Django admin在 Django admin 中为子模型添加按钮
【发布时间】:2019-05-30 22:04:12
【问题描述】:

Django 1.11。我有 2 个模型,FooBar

class Foo(models.Model):
    name = models.CharField()

class Bar(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Foo)

在 Django 管理员的 Foo 详细信息页面中,我在 Foo 详细信息下方列出了所有子 Bars:

@admin.register(Foo)
class FooAdmin(admin.ModelAdmin):
    def bars(self):
        html = ''
        bs = self.bar_set.all()
        for b in bs:
            html += '<a href="%s">%s</a><br>' % (reverse('admin:app_bar_change', args=(b.id,)), b.name)
        html += '<a href="%s">Add a bar</button>' % (reverse('admin:app_bar_add'))
        return html

    bars.allow_tags = True
    fields = ('name', bars)
    readonly_fields = (bars,)

如您所见,我还添加了一个按钮来添加新的Bar。这可行,但我想要的是在添加新的Bar 时自动预填充Foo 下拉列表。 IE。我想在当前打开的Foo 中添加一个Bar。我如何在 Django 中做到这一点?

【问题讨论】:

  • 您可以使用InlineModelAdmin.show_change_link 链接到每个内联的更改页面。如果您不想使用内联,最好让bar 中的外键指向foo 而不是相反,这将自动使用必要的小部件和javascript 插件来实现此功能。
  • @raratiru 据我了解,bar 中的外键已经指向foo,不是吗?
  • 确实!我的意思是相反的,从foo 指向bar 的外键。从 Django 2.0 开始,还有一个名为 autocomplete_fields 的新功能。你仍然可以随意修改并实现你想要的,甚至覆盖ModelForm 并定义一个ModelMultipleChoiceField,但我不确定它是否值得,即使它有效。
  • 我切换外键的问题是Foo 可以有很多Bars。不过感谢您的建议!
  • 我会在家里尝试一下,看看在 ModelForm 中定义一个带有多对多小部件的自定义字段是否会产生可行的结果。在Foo 中创建bar = models.ManyToManyField() 是不可能的吗?

标签: python django


【解决方案1】:

为此,django 允许您在管理类中包含 inlines。例如,以下将在表格中显示相关对象,而不显示用于更改 name 字段值的表单;

class BarInline(admin.TabularInline):
    model = Bar
    fields = (
        'name'
    )
    readonly_fields = (
        'name'
    )
    show_change_link = True

@admin.register(Foo)
class FooAdmin(admin.ModelAdmin):
    fields = ('name', )
    inlines = [
        BarInline,
    ]

通过设置show_change_link,您可以显示内联对象的更改链接,我相信这是您真正想要的。

Django 提供了InlineModelAdmin 的两个子类,它们是:

  • TabularInline
  • StackedInline

这两者之间的区别仅仅是用于渲染它们的模板。

如果这些内联不能满足您的需求,您可以创建自己的以使用自定义模板。

from django.contrib.admin.options import InlineModelAdmin


class ListInlineAdmin(InlineModelAdmin):
    template = 'admin/edit_inline/list.html'

然后在新的list.html 模板中,您可以让它显示对象名称并根据需要更改 URL。

【讨论】:

  • 谢谢,我知道内联,但我不希望下面的几十个大型表单堆积在同一页面上。因此是指向不同页面的链接列表。
  • @GluePear 好的,用不同的模板实现你自己的内联类可能是明智的,我会更新我的答案。
  • @GluePear 具有自定义内联模板的解决方案将业务逻辑与设计逻辑分开。因此,它有更多的机会承受重负载甚至可能的重重构。 (Django 更新)
【解决方案2】:

我在this SO answer 中找到了解决方案。可以在 URL 的查询字符串中指定预填充的字段。所以我的代码现在看起来像这样:

if self.id:    
    html += '<a href="%s?foo=%d">Add a bar</a>' % (reverse('admin:app_bar_add'), self.id)

编辑:我需要先检查实例是否有id,即它是否已经被保存。

【讨论】:

  • 如果当前的Foo 实例没有保存,这会起作用吗?
  • 非常好。在这种情况下,我将不得不隐藏按钮,直到实例被保存。
猜你喜欢
  • 2019-10-19
  • 2023-03-06
  • 1970-01-01
  • 2013-10-28
  • 2021-10-02
  • 2018-03-13
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多