【问题标题】:Show children inline in Django admin在 Django admin 中显示内联子项
【发布时间】:2019-01-03 15:54:05
【问题描述】:

在 Django 1.11 中,我有 2 个模型,Foo 和 Bar:

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

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

当我访问 Django 管理员中的 Foo 页面时,我希望能够在其下方看到其 Bars 的列表。所以我在admin.py:

class BarInline(admin.StackedInline):
    model = Bar

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

但我真正想要的是一个指向单独页面的可点击链接列表,我可以在其中编辑每个 Bar(以及添加按钮以向此 Foo 添加新 Bar)。 IE。我不想要整个内联表单。这在 Django 中怎么可能?

【问题讨论】:

    标签: python django


    【解决方案1】:
    admin.py
    
    from django.urls import reverse
    from django.utils.html import format_html_join
    
    @admin.register(Foo)
    class FooAdmin(admin.ModelAdmin):
        list_display = ('name')
        fields = ('name', get_related, )
        readonly_fields = (get_related, )
    
        def get_related(self, instance):
            obj = instance.bar_set.all()
            return format_html_join(
                ',',
                '<a href="{}">{}</a>',
                ((
                    reverse('admin:{{ app_label }}_bar_change', args=(c.id,)), 
                    c.name
                ) for c in obj),
            )
    

    您可以创建一个可调用的readonly field,它将返回包装在相关html code 中的每个关系的反转admin url。

    这将导致类似:

    “你的只读字段”:link1、link2、link3

    【讨论】:

    • 感谢您的详细回复。不幸的是,这没有输出任何 HTML。
    • @GluePear Reverse relations 以&lt;model_name&gt;_set 调用,除非您设置related_name。我认为,如果出错,这个可调用对象会默默地失败。试试:&gt;&gt;&gt; p = Foo.objects.first(),然后是&gt;&gt;&gt;dir(p),看看如何调用相关的Bar。否则,安装ipdb 并尝试在return 之前设置import pdb; pdb.set_trace() # XXX BREAKPOINT 以获得调试提示。
    • @GluePear admin:yourapp_bar_change 中还有一个陷阱。 yourapp 是您的模型 Bar 所在的应用程序的名称。yourproject/yourapp/models.py。当您更改模型 Bar 的实例时,您还可以在管理 url 中找到它:类似于 http://127.0.0.1/admin/yourapp/bar/1/change/。我在文档中将yourapp 更改为{{ app_label }}。
    • 感谢您的坚持。我的问题是我还需要在我的fields 变量(以及readonly_fields)中指定get_related。
    • @GluePear 哦,确实,我盲目地复制粘贴了代码,在我的实现中我有fileds='__all__'。
    【解决方案2】:

    您可以将BarInline 中的所有字段设为只读。

    class BarInline(admin.StackedInline):
        model = Bar
        readonly_fields = ('id', 'name', 'foo')
        extra = 0
    

    对于添加功能,您可以修改内联模板或更简单的方法,在FooAdmin 中添加一个自定义字段,例如:

    class FooAdmin(admin.ModelAdmin):
        list_display = ('name')
        fields = ('name', 'custom_add_bar')
        inlines = [BarInline]
    
        def custom_add_bar(self, obj):
            add_url = reverse('admin:appname_bar_add')
            return mark_safe(f'<a href="{add_url}">Add Bar</a>')
    

    Documentation for reversing admin urls

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 2011-02-23
      • 1970-01-01
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多