Django InlineModelAdmin:部分显示内联模型并链接到完整模型

Posted

技术标签:

【中文标题】Django InlineModelAdmin:部分显示内联模型并链接到完整模型【英文标题】:Django InlineModelAdmin: Show partially an inline model and link to the complete model 【发布时间】:2011-01-08 09:55:54 【问题描述】:

我定义了几个模型:Journals、volumes、volume_scanInfo 等。

一个期刊可以有更多的卷,一个卷可以有更多的scanInfo。

我想做的是:

在期刊的管理页面中,我希望将卷列表内联(完成) 将上一个列表的每个卷连接到其管理页面,我可以在其中显示用于编辑卷的表单及其内联“扫描信息”列表。

所以我想要类似的东西:

Journal #1 admin page
[name]
[publisher]
[url]
.....
list of volumes inline
    [volume 10] [..(other fields)..]   <a href="/link/to/volume/10">Full record</a>
    [volume 20] [..(other fields)..]   <a href="/link/to/volume/20">Full record</a>

然后

Volume #20 admin page
[volume number]
[..(other fields)...]
......
list of the scan info inline
    [scan info 33] [..(other fields)..]   <a href="/link/to/scaninfo/33">Full record</a>
    [scan info 44] [..(other fields)..]   <a href="/link/to/scaninfo/44">Full record</a>

我试图做的是定义一个模型方法来创建代码并尝试在管理中定义“volume inline”的类中使用它,但它不起作用。

换句话说

“Volume”模型的内部类似于:

def selflink(self):
    return '<a href="/admin/journaldb/volume/%s/">Full record</a>' % self.vid
selflink.allow_tags = True

class VolumeInline(admin.TabularInline):
    fields = ['volumenumber', 'selflink']
    model = Volume
    extra = 1

但这会产生以下错误:

Exception Value: 'VolumeInline.fields' refers to field 'selflink' that is missing from the form.

有什么想法吗?

谢谢, 乔瓦尼

【问题讨论】:

非常好的问题。这种功能应该是内置的。 iI 是内置的。自 django 1.8 以来,它在此处回答 (show_change_link):***.com/a/28170958/493272 我知道,但是这个问题已经 6 岁了 :-) 我会更新答案,所以很明显有这个新功能。 【参考方案1】:

更新: 从 Django 1.8 开始,这是内置的。

请参阅 this answer 和 the official documentation。

旧答案:

最后我找到了一个简单的解决方案。

我创建了一个名为linked.html 的新模板,它是tabular.html 的副本,我添加了这段代码来创建链接。

% if inline_admin_form.original.pk %
          <td class=" field.field.name ">
              <a href="/admin/ app_label / inline_admin_formset.opts.admin_model_path / inline_admin_form.original.pk /">Full record</a>
          </td>
% endif %

然后我创建了一个新模型LinkedInline 继承InlineModelAdmin

#override of the InlineModelAdmin to support the link in the tabular inline
class LinkedInline(admin.options.InlineModelAdmin):
    template = "admin/linked.html"
    admin_model_path = None

    def __init__(self, *args):
        super(LinkedInline, self).__init__(*args)
        if self.admin_model_path is None:
            self.admin_model_path = self.model.__name__.lower()

然后当我定义一个新的内联时,我只需要使用我的LinkedInline 而不是普通的InlineModelAdmin

我希望它对其他人有用。

乔瓦尼

【讨论】:

当您保存子模型页面时,它会返回到父模型页面吗? 如果您正在编辑链接到期刊的完整卷模型,当您保存时,它会自动返回期刊编辑页面吗? 不,如果您在完整的卷管理页面内,则保存后您将留在此处。但是由于该卷有期刊作为外键,所以我扩展了外键形式,打印了一个返回期刊的链接,这样你就可以一键返回。 LinkedInline如何找到模板文件?您是否将模板文件放入现有模板目录中,而不是放入带有 LinkedInline.py 文件的“模块”中? 忽略我最后的评论...原来真正的问题是我的远程对象显然没有主键(这是 BS,因为我定义了一个...)【参考方案2】:

更新:

从 Django 1.8 开始,现在是 built-in。

Django

将您的代码保存在 models.py 中并带有条件大小写:

def selflink(self):
    if self.id:
        return "<a href='/link/to/volume/%s' target='_blank'>Edit</a>" % str(self.id)
    else:
        return "Not present"

selflink.allow_tags = True

admin.py中,添加selflink为readonly字段:

class VolumeInline(admin.TabularInline):
    readonly_fields = ['selflink',]
    model = Volume

这对我有用。

【讨论】:

如果你使用fields选项,你需要把它放在readonly_fields之后 @uszywieloryba:在 Django-1.4.x 中不正确。无论如何,selflink 必须在fieldsfieldsets 中。 我更喜欢在 models.py 中编写代码而不是在模板中编写代码!谢谢【参考方案3】:

这是基于其他一些答案的可重复使用的 mixin。这很方便,因为它适用于 Tabular 和 Stacked 内联,并且不会破坏您的模型或管理代码。

# put this somewhere like admin_helpers.py
from django.core.urlresolvers import reverse

class InlineEditLinkMixin(object):
    readonly_fields = ['edit_details']
    edit_label = "Edit"
    def edit_details(self, obj):
        if obj.id:
            opts = self.model._meta
            return "<a href='%s' target='_blank'>%s</a>" % (reverse(
                'admin:%s_%s_change' % (opts.app_label, opts.object_name.lower()),
                args=[obj.id]
            ), self.edit_label)
        else:
            return "(save to edit details)"
    edit_details.allow_tags = True

# admin.py

class VolumeInline(InlineEditLinkMixin, admin.TabularInline):
    fields = ['foo', 'bar', 'edit_details']

class JournalAdmin(admin.ModelAdmin):
    inlines = [VolumeInline]

class ScanInfoInline(InlineEditLinkMixin, admin.StackedInline):
    fields = ['foo', 'bar', 'edit_details']

class JournalAdmin(admin.ModelAdmin):
    inlines = [ScanInfoInline]

【讨论】:

非常有帮助和整洁。我需要在你的代码上添加这个from django.core.urlresolvers import reverse 我想知道这是否可以自动与 many2many 字段集一起使用,您在哪里有model = ModelA.modelbs.through?它需要检测到这一点(可能通过_meta.auto_created?)并相应地创建编辑链接。【参考方案4】:

在Django 1.8+ this is now much easier。只需将show_change_link = True 添加到您的TabularInlineStackedInline 子类中,如下所示:

class VolumeInline(admin.TabularInline):
    fields = ['volumenumber']
    model = Volume
    extra = 1
    show_change_link = True

如果模型有自己注册的ModelAdmin,Django 会自动为每个内联项添加完整更改表单的链接。

【讨论】:

【参考方案5】:

你试过Reversing admin URL系统吗? 这可能会给出类似的东西(在期刊页面中):

<ul>
% for volume in original.volume_set.all %
  <li>
    <a href="% url admin:yourapp_volume_change volume.id %">Edit  volume 
    </a>
  </li>
% endfor %
</ul>

【讨论】:

【参考方案6】:

经过一番折腾,我能够使用 reverse() 在 InlineAdmin 和 TabularInline 中完成这项工作。至少对于 TabularInline,您要链接的字段必须列在“readonly_fields”中

# create a read-only inline with the first field linked
from django.core import urlresolvers
class YOUR_MODEL_Inline(LinkedTabularInline):
    max_num = 0 # remove the "Add another ..." link
    model = YOUR_MODEL_NAME
    fk_name = "YOUR_FOREIGN_KEY_NAME"
    fields = [ 'link_name', ] # , 'field1', 'field2', 'etc' ]
    readonly_fields = fields
    can_delete = False
    def link_name(self, obj):
        if obj.pk:
            url = urlresolvers.reverse('admin:%s_%s_change'
                % (obj._meta.app_label, obj._meta.module_name), args=[obj.id])
            # obj.MODEL_FIELD can be a text string or whatever you want
            return '<a href="0">1</a>'.format(url, obj.MODEL_FIELD) 
    link_name.allow_tags = True
    link_name.short_description = "MODEL_FIELD"

如果您想链接到更改列表而不是更改视图,您可以修改 reverse() 调用。更改列表不需要对象 ID。

    url = urlresolvers.reverse('admin:%s_%s_changelist' 
        % (obj._meta.app_label, obj._meta.module_name))
    return '<a href="0">1</a>'.format(url, obj.name)

如果你想链接到对象的子集,你可以在 URL 中添加参数:

    return '<a href="0?YOUR_MODEL_FIELD__id__exact=1">2</a>'.format(url, obj.id, obj.name)

【讨论】:

以上是关于Django InlineModelAdmin:部分显示内联模型并链接到完整模型的主要内容,如果未能解决你的问题,请参考以下文章

Django InlineModelAdmin:部分显示内联模型并链接到完整模型

InlineModelAdmin对象的学习

显示嵌套模型的InlineModelAdmin

如何从管理上下文数据中找到InlineModelAdmin?

使用 Django 1.8 的 show_change_link,“保存”按钮返回错误页面

如何在 Django 模板中发出外部网站的 HTML?