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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2120813/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 23:51:04  来源:igfitidea点击:

Django InlineModelAdmin: Show partially an inline model and link to the complete model

pythondjangodjango-admin

提问by Giovanni Di Milia

I defined several models: Journals, volumes, volume_scanInfo etc.

我定义了几个模型:期刊、卷、volume_scanInfo 等。

A journal can have more volumes and a volume can have more scanInfo.

一个日志可以有更多的卷,一个卷可以有更多的 scanInfo。

What I want to do is:

我想做的是:

  • in the admin page of journals I want to have the list of the volumes inline (done)
  • connect each volume of the previous list to its admin page where I can show the form to edit the volume and the list of its "scan info" inline.
  • 在期刊的管理页面中,我想要内联的卷列表(完成)
  • 将上一个列表的每个卷连接到其管理页面,我可以在其中显示用于编辑卷及其内联“扫描信息”列表的表单。

so I want to have something like:

所以我想要一些类似的东西:

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>

Then

然后

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>

What I tried to do is defining a model method that create the code and trying to use it inside the class that defines "volume inline" in the admin, but it doesn't work.

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

In other words

换句话说

the model "Volume" has inside something like:

模型“Volume”里面有类似的东西:

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

and

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

But this gives the following error:

但这会产生以下错误:

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

Any idea?

任何的想法?

Thanks, Giovanni

谢谢,乔瓦尼

采纳答案by Giovanni Di Milia

UPDATE:Since Django 1.8, this is built in.

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

See this answerand the official documentation.

请参阅此答案官方文档

OLD ANSWER:

旧答案:

At the end I found a simple solution.

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

I create a new template called linked.htmlthat is a copy of tabular.htmland I added this code to create the link.

我创建了一个名为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 %}

then I created a new model LinkedInlineinheriting InlineModelAdmin

然后我创建了一个新模型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()

Then when I define a new inline, I have only to use my LinkedInlineinstead of the normal InlineModelAdmin.

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

I hope it can be useful for other people.

我希望它对其他人有用。

Giovanni

乔瓦尼

回答by yasc

Update:

更新:

As of Django 1.8, this is now built-in.

从 Django 1.8 开始,它现在是内置的

Answer for Django <= 1.7:

Django <= 1.7 的答案:

Keep your code in models.pywith conditional case:

将您的代码保存在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

In admin.py, add selflink as readonlyfield:

admin.py 中,添加 selflink 作为只读字段:

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

That worked for me.

那对我有用。

回答by Hyman Cushman

Here's a reusable mixin based on some of the other answers. This is handy because it works with both Tabular and Stacked inlines, and doesn't cruft up your model or admin code.

这是基于其他一些答案的可重用 mixin。这很方便,因为它适用于表格和堆叠内联,并且不会弄乱您的模型或管理代码。

# 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]

回答by Carl Meyer

In Django 1.8+ this is now much easier. Just add show_change_link = Trueto your TabularInlineor StackedInlinesubclass, like this:

Django 1.8+ 中,这现在更容易了。只需添加show_change_link = True到您的TabularInlineStackedInline子类中,如下所示:

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

And Django will automatically add a link to the full change form for each inline item, if the model has its own registered ModelAdmin.

如果模型有自己的注册ModelAdmin.

回答by Pierre de LESPINAY

Did you try the Reversing admin URLsystem ?
That could give something like that (in the journal page):

您是否尝试过反向管理 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>

回答by Eli Burke

After some fiddling, I was able to make this work in an InlineAdmin and a TabularInline, using reverse(). At least with TabularInline, the field you want to link mustbe listed in 'readonly_fields'

经过一番折腾,我能够使用 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"

If you want to link to the change list instead of the change view, you can modify the reverse() call. changelist does not require an object id.

如果要链接到更改列表而不是更改视图,可以修改 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)

And if you want to link to a subset of objects, you can add parameters to the URL:

如果要链接到对象的子集,可以向 URL 添加参数:

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