Django 管理后台 - 内联内联(或同时编辑三个模型)

53 投票
4 回答
32444 浏览
提问于 2025-04-15 11:04

我有一组模型,长得像这样:

class Page(models.Model):
    title = models.CharField(max_length=255)

class LinkSection(models.Model):
    page = models.ForeignKey(Page)
    title = models.CharField(max_length=255)

class Link(models.Model):
    linksection = models.ForeignKey(LinkSection)
    text = models.CharField(max_length=255)
    url = models.URLField()

还有一个admin.py文件,内容是这样的:

class LinkInline(admin.TabularInline):
    model = Link
class LinkSectionInline(admin.TabularInline):
    model = LinkSection
    inlines = [ LinkInline, ]
class PageAdmin(admin.ModelAdmin):
    inlines = [ LinkSectionInline, ]

我的目标是想要一个管理界面,可以让我在一页上编辑所有内容。这个模型结构的最终结果是生成一个视图和模板,基本上看起来像这样:

<h1>{{page.title}}</h1>
{% for ls in page.linksection_set.objects.all %}
<div>
    <h2>{{ls.title}}</h2>
    <ul>
         {% for l in ls.link_set.objects.all %}
        <li><a href="{{l.url}}">{{l.title}}</a></li>
         {% endfor %}
    </ul>
</div>
{% endfor %}

我知道在Django的管理界面中,嵌套嵌套的方式是行不通的,正如我预料的那样。有没有人知道怎么实现这种三层模型的编辑呢?提前谢谢大家。

4 个回答

1

我建议你可以考虑改变一下你的模型。为什么不在Link里加一个指向LinkSectionForeignKey呢?或者,如果不是一对多的关系,可能可以用ManyToMany字段?这样的话,后台管理界面会自动生成这些关系。当然,如果链接和链接部分之间没有逻辑上的关系,我就不推荐这样做了,但也许它们之间是有关系的?如果没有,请解释一下你想要的组织方式是什么。(比如,每个部分固定有3个链接,还是说可以随意调整?)

5

Django-nested-inlines 是专门为这个目的而创建的。使用起来很简单。

from django.contrib import admin
from nested_inlines.admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline
from models import A, B, C

class MyNestedInline(NestedTabularInline):
    model = C

class MyInline(NestedStackedInline):
    model = B
    inlines = [MyNestedInline,]

class MyAdmin(NestedModelAdmin):
    pass

admin.site.register(A, MyAdmin)
22

你需要为 LinkSectionInline 创建一个自定义的 表单模板

像下面这样的代码应该可以用来创建表单:

LinkFormset = forms.modelformset_factory(Link)
class LinkSectionForm(forms.ModelForm):
    def __init__(self, **kwargs):
        super(LinkSectionForm, self).__init__(**kwargs)
        self.link_formset = LinkFormset(instance=self.instance, 
                                        data=self.data or None,
                                        prefix=self.prefix)

    def is_valid(self):
        return (super(LinkSectionForm, self).is_valid() and 
                    self.link_formset.is_valid())

    def save(self, commit=True):
        # Supporting commit=False is another can of worms.  No use dealing
        # it before it's needed. (YAGNI)
        assert commit == True 
        res = super(LinkSectionForm, self).save(commit=commit)
        self.link_formset.save()
        return res

(这只是我随便想的,没经过测试,但应该能帮你朝着正确的方向前进。)

你的模板只需要正确地显示表单和 form.link_formset 就可以了。

撰写回答